Rails:如何包含相关模型的表单

时间:2012-10-10 14:13:17

标签: ruby-on-rails-3 has-many-through rails-routing

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

以下是模型定义:

# 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资源嵌套在store资源下,如下所示:

resources :stores do
  resources :employees
end

编辑:我还添加了资源:员工作为“unnested”资源。所以现在看起来像这样:

resources :stores do
  resources :employees
end
resources :employees

所以,在商店控制器的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中的NoMethodError #create

     

的未定义方法`employee_url'

那么,我错过了什么?我认为这与'form_for'有关,但我不确定。我不确定为什么要调用EmployeesController #create。我在使用routes.rb做错了吗?

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

###更新

这是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)

1 个答案:

答案 0 :(得分:1)

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

redirect_to @employee

这会尝试使用employee_url,但这不存在,因为您已在路径文件中嵌套了employees资源。解决方案是添加“unnested”资源:

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