如何获得强参数以允许嵌套的fields_for属性?

Coe*_*ulf 3 ruby-on-rails strong-parameters ruby-on-rails-4

我有一个带有嵌套fields_for的表单.我试图允许由该嵌套表单生成的参数,但它们被强参数阻止.我使用rails 4.2.4和ruby 2.2.2

我读过一些官方文档:

我已经阅读了相关的SO帖子:

我读过各种博文:

我想我正在按照他们的意思去做,但是我的嵌套属性被强参数拒绝了.我Unpermitted parameters: __template_row__, 0, 1, 2, 3在日志中得到的东西.

这是我的代码:

车型/ enclosure.rb

class Enclosure < ActiveRecord::Base
  has_many :resident_animals, -> { order("year DESC, month DESC") }, dependent: :restrict_with_error
  validates :name, presence: true, uniqueness: {case_sensitive: false}

  accepts_nested_attributes_for :resident_animals, allow_destroy: true, reject_if: :all_blank

  def to_s
    name
   end
end
Run Code Online (Sandbox Code Playgroud)

车型/ resident_animal.rb

class ResidentAnimal < ActiveRecord::Base
  belongs_to :enclosure

  validates_presence_of :enclosure, :year, :month, :color
  ...
end
Run Code Online (Sandbox Code Playgroud)

控制器/ enclosures_controller.rb

class EnclosuresController < ApplicationController
  ...
  def update
    @enclosure = Enclosure.find(params[:id])
    @enclosure.update(enclosure_params)
    respond_with @enclosure
  end

  private

  def enclosure_params
    params.require(:enclosure).permit(:name, :description, resident_animals_attributes: [:year, :month, :color, :id, :_destroy])
  end
end
Run Code Online (Sandbox Code Playgroud)

视图/隔音罩/ _form.html.erb

<p class="field">
  <%= form.label :name %>
  <%= form.text_field :name %>
</p>

<p class="field">
  <%= form.label :description %>
  <%= form.text_area :description %>
</p>

<fieldset>
  <legend>Resident Animals</legend>

  <table id="resident-animal-rows">
    <thead>
      <th>Year <span class="required-field">*</span></th>
      <th>Month <span class="required-field">*</span></th>
      <th>Color <span class="required-field">*</span></th>
      <th>Remove</th>
    </thead>
    <tbody>
      <%= form.fields_for :resident_animals_attributes, ResidentAnimal.new(channel: form.object, year: Date.current.year, month: Date.current.month), index: "__template_row__" do |resident_animal_fields| %>
      <tr class="resident-animal-row row-template">
        <td><%= resident_animal_fields.number_field :year %></td>
        <td><%= resident_animal_fields.select :month, month_options, include_blank: true %></td>
        <td><%= resident_animal_fields.text_field :color %></td>
        <td class="checkbox-cell"><%= resident_animal_fields.check_box :_destroy %></td>
      </tr>
      <% end %>
      <%= form.fields_for :resident_animals do |resident_animal_fields| %>
        <tr class="resident-animal-row">
          <td><%= resident_animal_fields.number_field :year %></td>
          <td><%= resident_animal_fields.select :month, month_options, include_blank: true %></td>
          <td><%= resident_animal_fields.text_field :color %></td>
          <td class="checkbox-cell">
            <%= resident_animal_fields.hidden_field :id %>
            <%= resident_animal_fields.check_box :_destroy %>
          </td>
        </tr>
      <% end %>
    </tbody>
  </table>
  <%= link_to "Add resident animal", "#", class: "resident-animal-row-add" %>
</fieldset>
Run Code Online (Sandbox Code Playgroud)

当我记录我的参数时,它们看起来像:

{"enclosure"=>{"name"=>"Polar Quest", "description"=>"Polar bear attraction", "resident_animals_attributes"=>{"__template_row__"=>{"year"=>"2015", "month"=>"9", "color"=>"", "_destroy"=>"0"}, "0"=>{"year"=>"2005", "month"=>"8", "color"=>"white", "id"=>"1", "_destroy"=>"0"}, "1"=>{"year"=>"2012", "month"=>"7", "color"=>"yellow", "id"=>"2", "_destroy"=>"0"}, "2"=>{"year"=>"2011", "month"=>"3", "color"=>"white", "id"=>"4", "_destroy"=>"0"}, "3"=>{"year"=>"2006", "month"=>"2", "color"=>"yellowish", "id"=>"3", "_destroy"=>"0"}}}, "commit"=>"Update", "id"=>"1"}
Run Code Online (Sandbox Code Playgroud)

调用enclosure_params返回:

{"name"=>"Polar Quest", "description"=>"Polar bear attraction", "resident_animals_attributes"=>{}}
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

mlt*_*tsy 5

谢谢!

我将在这里添加您的评论中的正确答案,这样这个问题就可以得到正确答案:

问题.permit在于 - 包含ID作为键的嵌套哈希和作为值的其他属性的哈希值是一种特殊情况(很明显,因为它与典型的参数结构不匹配.permit).

诀窍是:算法检测特殊情况(称为fields_for_style?因为它是fields_for助手通常提交的参数样式),并且只有当所有键都转换为整数时!因此,如果密钥集中有非整数值(例如__template_row__new_record_id),它将不会检测特殊情况,而是拒绝未明确允许的散列中的每个密钥(对于任何典型的哈希).

为了解决这个问题,给定原始帖子中的params结构,您可以简单地删除作为模板行的一部分提交的非整数键和属性:

def enclosure_params
  params[:enclosure][:resident_animals_attributes].delete(:__template_row__)
  params.require(:enclosure).permit(...) # (no change from OP)
end
Run Code Online (Sandbox Code Playgroud)

(当然这意味着,您应该确保您的界面不会尝试将有意义的数据作为模板行的一部分提交);)