如何获得强参数以允许嵌套 fields_for 属性?
How can I get strong parameters to permit nested fields_for attributes?
我有一个带有嵌套 fields_for 的表单。我试图允许由该嵌套表单生成的参数,但它们被强参数阻止了。我正在使用 rails 4.2.4 和 ruby 2.2.2
我看过一些官方文档:
- http://api.rubyonrails.org/classes/ActionController/StrongParameters.html
- http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
我已经阅读了相关的 SO 帖子:
- Rails 4 Nested Attributes Unpermitted Parameters
我阅读了各种博客文章:
- http://www.rubyexperiments.com/using-strong-parameters-with-nested-forms/
- http://adamyonk.com/2013/05/16/rails-4-strong-parameters-and-nested-forms.html
- 以及更多
我想我是按照他们说的去做,但是我的嵌套属性被强参数拒绝了。我在我的日志中得到类似 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 returns:
{"name"=>"Polar Quest", "description"=>"Polar bear attraction", "resident_animals_attributes"=>{}}
我做错了什么?
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|
您没有定义索引属性。尝试删除该键值对。
谢谢!
我将从您的评论中添加正确答案,这样这个问题就有了正确答案:
问题是 .permit
-ing 嵌套散列,其中包括 ID 作为键和其他属性的散列作为值是一种特殊情况(很明显,因为它不匹配.permit
).
的典型参数结构
诀窍是:当且仅当所有键转化为整数!因此,如果键集中有非整数值(例如 __template_row__
或 new_record_id
),它不会检测特殊情况,而是拒绝散列中不是整数的每个键明确允许(对于任何典型的散列)。
为了解决这个问题,鉴于原始 post 的参数结构,您可以简单地删除作为模板行的一部分提交的非整数键和属性:
def enclosure_params
params[:enclosure][:resident_animals_attributes].delete(:__template_row__)
params.require(:enclosure).permit(...) # (no change from OP)
end
(当然这意味着,您应该确保您的界面不会尝试提交有意义的数据作为模板行的一部分);)
我有一个带有嵌套 fields_for 的表单。我试图允许由该嵌套表单生成的参数,但它们被强参数阻止了。我正在使用 rails 4.2.4 和 ruby 2.2.2
我看过一些官方文档:
- http://api.rubyonrails.org/classes/ActionController/StrongParameters.html
- http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
我已经阅读了相关的 SO 帖子:
- Rails 4 Nested Attributes Unpermitted Parameters
我阅读了各种博客文章:
- http://www.rubyexperiments.com/using-strong-parameters-with-nested-forms/
- http://adamyonk.com/2013/05/16/rails-4-strong-parameters-and-nested-forms.html
- 以及更多
我想我是按照他们说的去做,但是我的嵌套属性被强参数拒绝了。我在我的日志中得到类似 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 returns:
{"name"=>"Polar Quest", "description"=>"Polar bear attraction", "resident_animals_attributes"=>{}}
我做错了什么?
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|
您没有定义索引属性。尝试删除该键值对。
谢谢!
我将从您的评论中添加正确答案,这样这个问题就有了正确答案:
问题是 .permit
-ing 嵌套散列,其中包括 ID 作为键和其他属性的散列作为值是一种特殊情况(很明显,因为它不匹配.permit
).
诀窍是:当且仅当所有键转化为整数!因此,如果键集中有非整数值(例如 __template_row__
或 new_record_id
),它不会检测特殊情况,而是拒绝散列中不是整数的每个键明确允许(对于任何典型的散列)。
为了解决这个问题,鉴于原始 post 的参数结构,您可以简单地删除作为模板行的一部分提交的非整数键和属性:
def enclosure_params
params[:enclosure][:resident_animals_attributes].delete(:__template_row__)
params.require(:enclosure).permit(...) # (no change from OP)
end
(当然这意味着,您应该确保您的界面不会尝试提交有意义的数据作为模板行的一部分);)