2

我有一个使用“has_many :through”关系的 Rails 应用程序。我有 3 个表/模型。它们是 Employee、Store 和 StoreEmployee。一名员工可以为一家或多家商店工作。在 Store 视图 (show.html.erb) 上,我想包含一个表单以将员工添加到商店。如果员工尚不存在,则将其添加到员工表中。如果它已经存在,它只是被添加到存储中。

以下是模型定义:

# models
class Employee < ActiveRecord::Base
  has_many :store_employees
  has_many :stores, :through => :store_employees
  attr_accessible :email, :name
end

class Store < ActiveRecord::Base
  has_many :store_employees 
  has_many :employees, :through => :store_employees
  attr_accessible :address, :name
end

class StoreEmployee < ActiveRecord::Base
  belongs_to :store
  belongs_to :employee
  attr_accessible :employee_id, :store_id
end

使用 rails 控制台,我可以证明数据模型工作正常,如下所示:

emp = Employee.first
str = Store.first
str.employees << emp    # add the employee to the store
str.employees           # shows the employees that work at the store
emp.stores              # shows the stores where the employee works

我还更新了我的 routes.rb 以将 employees 资源嵌套在 stores 资源下,如下所示:

resources :stores do
  resources :employees
end

编辑:我还将资源 :employees 添加为“未嵌套”资源。所以现在看起来像这样:

resources :stores do
  resources :employees
end
resources :employees

所以,在 store 控制器的 show 动作中,我认为它应该是这样的:

def show
  @store = Store.find(params[:id])
  @employee = @store.employees.build     # creating an empty Employee for the form

  respond_to do |format|
    format.html # show.html.erb
    format.json { render json: @store }
  end
end

这是商店的 show.html.erb,包括添加员工的表单:

<p id="notice"><%= notice %></p>

<p>
  <b>Name:</b>
  <%= @store.name %>
</p>

<p>
  <b>Address:</b>
  <%= @store.address %>
</p>

<%= form_for([@store, @employee]) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>

<%= f.label :email %>
<%= f.text_field :email %>

<%= f.submit "Add Employee" %>
<% end %>

<%= link_to 'Edit', edit_store_path(@store) %> |
<%= link_to 'Back', stores_path %>

单击“添加员工”按钮时,我收到此错误消息:

EmployeesController#create 中的 NoMethodError

# 未定义的方法`employee_url'

那么,我错过了什么?我认为这与“form_for”有关,但我不确定。我不知道为什么EmployeesController#create 被调用。我对 routes.rb 做错了吗?

我不知道添加员工的逻辑应该去哪里。在员工控制器中?存储控制器?

### 更新

这是EmployeesController 中更新的create 方法。我包括了米沙回答中的建议。

def create
  @store = Store.find(params[:store_id])
  @employee = @store.employees.build(params[:employee])

  respond_to do |format|
    if @employee.save
      format.html { redirect_to @store, notice: 'Employee was successfully created.' }
      format.json { render json: @employee, status: :created, location: @employee }
    else
      format.html { render action: "new" }
      format.json { render json: @employee.errors, status: :unprocessable_entity }
    end
  end
end

进行此更改后,我成功保存了 Employee,但未创建 store_employees 关联记录。我不知道为什么。这是创建记录时我的终端中的输出。请注意,商店是 SELECTed 并且 Employee 是 INSERTed ,但仅此而已。任何地方都没有 store_employees 记录:

Started POST "/stores/1/employees" for 127.0.0.1 at 2012-10-10
13:06:18 -0400 Processing by EmployeesController#create as HTML  
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"LZrAXZ+3Qc08hqQT8w0MhLYsNNSG29AkgCCMkEJkOf4=",
"employee"=>{"name"=>"betty", "email"=>"betty@kitchen.com"},
"commit"=>"Add Employee", "store_id"=>"1"}   Store Load (0.4ms) 
SELECT "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1 
[["id", "1"]]    (0.1ms)  begin transaction   SQL (13.9ms)  INSERT
INTO "employees" ("created_at", "email", "name", "updated_at") VALUES
(?, ?, ?, ?)  [["created_at", Wed, 10 Oct 2012 17:06:18 UTC +00:00],
["email", "betty@kitchen.com"], ["name", "betty"], ["updated_at", Wed,
10 Oct 2012 17:06:18 UTC +00:00]]    (1.3ms)  commit transaction
Redirected to http://localhost:3000/stores/1 Completed 302 Found in
23ms (ActiveRecord: 15.6ms)
4

1 回答 1

1

问题是由您的EmployeesController#create方法中的此代码段引起的:

redirect_to @employee

这尝试使用employee_url,但不存在,因为您已将 employees 资源嵌套在您的路线文件中。解决方案是还添加“未嵌套”资源:

resources :stores do
  resources :employees
end
resources :employees

或者只是重定向到不同的位置。例如回到StoresController#show.

顺便说一句,默认的脚手架不会做你期望它做的事情:它不会创建与商店相关的员工。为此,您必须对其进行一些重写:

def create
  @store = Store.find(params[:store_id])
  @employee = @store.employees.build(params[:employee])

  respond_to do |format|
    if @employee.save
      format.html { redirect_to @employee, notice: 'Employee was successfully created.' }
      format.json { render json: @employee, status: :created, location: @employee }
    else
      format.html { render action: "new" }
      format.json { render json: @employee.errors, status: :unprocessable_entity }
    end
  end
end
于 2012-10-10T15:09:52.357 回答