【问题标题】:How can I get strong parameters to permit nested fields_for attributes?如何获得强参数以允许嵌套 fields_for 属性?
【发布时间】:2015-12-08 09:16:09
【问题描述】:

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

我已经阅读了一些官方文档:

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

我已经阅读了各种博客文章:

我想我正在按照他们所说的去做,但是我的嵌套属性被强参数拒绝了。我的日志中出现Unpermitted parameters: __template_row__, 0, 1, 2, 3 之类的信息。

这是我的代码:

models/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

models/resident_animal.rb

class ResidentAnimal < ActiveRecord::Base
  belongs_to :enclosure

  validates_presence_of :enclosure, :year, :month, :color
  ...
end

controllers/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

views/enclosures/_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>

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

{"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"}

调用enclosure_params 返回:

{"name"=>"Polar Quest", "description"=>"Polar bear attraction", "resident_animals_attributes"=>{}}

我做错了什么?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 strong-parameters


    【解决方案1】:

    谢谢!

    我将在此处从您的评论中添加正确答案,以便此问题可以得到正确答案:

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

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

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

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

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

    【讨论】:

      【解决方案2】:
      def enclosure_params
        params.require(:).permit(:name, :description,
          resident_animals_attributes: [:enclosure_id, :year, :month, :color]
        )
      end
      

      我建议您使用新格式的 rails 验证:

      validates: :enclosure_id, presence: true    
      validates: :year, presence: true
      validates: :month, presence: true
      validates: :color, presence: true
      

      如果您确实需要在 resident_animal 上存在外壳,您可能需要在依赖模型上使用 inverse:。我不确定您是否需要该验证。

      错误是指这一行

      <%= 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| %>
      

      特别是

      index: "__template_row__" do |resident_animal_fields| 
      

      您没有定义索引属性。尝试删除该键值对。

      【讨论】:

      • 谢谢。这与正在发生的事情非常接近,以至于我能够追踪到它。问题是参数中存在"__template_row__" 键导致它拒绝整个事情。如果我在使用强参数之前从哈希中删除该键值对,它可以解决我的问题。如果你想更新你的答案,我会奖励你的帮助。
      • 谢谢。我不确定您认为我的答案应该如何更新。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-22
      • 2013-04-01
      • 2017-06-03
      • 2016-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多