Rails4:复杂的形式和嵌套的属性

Rails 4: Complex forms and nested attributes

我有一个 Rails 4 应用程序,其中有两个相关的控制器,potential_clientlocation。我正在尝试通过位置控制器创建潜在客户。我认为我的表单有问题,因为它作为 PATCH 提交到该位置,而不是创建一个新的 potential_client,如下所示:

class Location < ActiveRecord::Base
    validates_presence_of :name, :email, :address, :phone
    has_many :potential_clients
    accepts_nested_attributes_for :potential_clients
end

class PotentialClient < ActiveRecord::Base
    validates_presence_of :name, :email, :phone
    belongs_to :location
end

我的路由配置如下:

resources :locations do
    resources :potential_clients
end

在我的 app/views/locations/show.html.erb 中,我有以下表格:

<div class="form-container">
    <%= form_for @location do |f| %>
        <%= f.fields_for :potential_client do |pc_form| %>

            <%= pc_form.label :name %>
            <%= pc_form.text_field :name %><br />

            <%= pc_form.label :email %>
            <%= pc_form.email_field :email %><br />

            <%= pc_form.label :phone %>
            <%= pc_form.number_field :phone %><br />

            <%= pc_form.label :message %>
            <%= pc_form.text_field :message %><br />


            <%= pc_form.hidden_field :location_id, :value => @location.id %>

            <%= pc_form.submit "Submit" %>

        <% end %>
    <% end %>
</div>

表单加载正确,但是当我尝试提交内容时,我的控制台出现 Unpermitted parameter: potential_client 错误,但在我的 location_controller 中我有:

def location_params
    params.require(:location).permit(:name, :email, :address, :phone, :potential_client, potential_client_attributes: [:name, :email, :message, :phone])
end

...最重要的是,当我尝试创建 potential_client 时,我的控制台显示:

Started PATCH "/locations/1" for ::1 at 2016-02-03 13:18:27 -0500
ActiveRecord::SchemaMigration Load (0.1ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by LocationsController#update as HTML

所有有用的路线:

location_potential_clients     GET    /locations/:location_id/potential_clients(.:format)          potential_clients#index
                               POST   /locations/:location_id/potential_clients(.:format)          potential_clients#create
 new_location_potential_client GET    /locations/:location_id/potential_clients/new(.:format)      potential_clients#new
edit_location_potential_client GET    /locations/:location_id/potential_clients/:id/edit(.:format) potential_clients#edit
     location_potential_client GET    /locations/:location_id/potential_clients/:id(.:format)      potential_clients#show
                               PATCH  /locations/:location_id/potential_clients/:id(.:format)      potential_clients#update
                               PUT    /locations/:location_id/potential_clients/:id(.:format)      potential_clients#update
                               DELETE /locations/:location_id/potential_clients/:id(.:format)      potential_clients#destroy
                     locations GET    /locations(.:format)                                         locations#index
                               POST   /locations(.:format)                                         locations#create
                  new_location GET    /locations/new(.:format)                                     locations#new
                 edit_location GET    /locations/:id/edit(.:format)                                locations#edit
                      location GET    /locations/:id(.:format)                                     locations#show
                               PATCH  /locations/:id(.:format)                                     locations#update
                               PUT    /locations/:id(.:format)                                     locations#update
                               DELETE /locations/:id(.:format)                                     locations#destroy

可能是因为 :location_id:id 对于两条路线都是相同的,并且 Rails 是路由到位置而不是 potential_client

为什么要打补丁?

当你这样做时:

<%= form_for @location do |f| %>

rails 多态路由助手查看 @location 并使用 @location.new_record? 来查看它是否应该路由到 updatecreate.

因此,在您的 locations#show 操作中,您传递的是持久记录 - 因此它将路由到 update

如果你想有一个单独的表格只发布一个潜在客户,你会这样做:

<%= form_for [@location, @potential_client] do |f| %>

如果它是一条新记录,将创建一个 POST locations/1/potential_clients 请求;如果它已被保存,将创建一个 PATCH locations/1/potential_clients/1 请求。

嵌套属性

这是一个简单的复数错误。您的模型 accepts_nested_attributes_for :potential_clients 而您的表单 <%= f.fields_for :potential_client do |pc_form| %>.

当您使用 fields_for 时,应该使用与关系相同的名称 - 因此在 has_many 的情况下,它应该是复数形式。

<div class="form-container">
    <%= form_for @location do |f| %>
        <%= f.fields_for :potential_clients do |pc_form| %>
            # ...
        <% end %>
    <% end %>
</div>

请注意,正确的参数键是 potential_clients_attributes,因此您应该将其列入白名单。

def location_params
    params.require(:location)
          .permit(
            :name, :email, :address, :phone, 
            potential_clients_attributes: [:name, :email, :message, :phone]
          )
end