Rails 4嵌套的属性不允许的参数

我是RoR的新手,但已经决定我可以在4学习。这可能或不是一个好主意。 我正在尝试创build一个使用嵌套属性的表单,我挣扎着。

我看了这个railscast http://railscasts.com/episodes/196-nested-model-form-part-1 ,我试图重新创build一个类似的情况我自己。

我有一个Bill对象,有许多Due对象。 Due对象也属于Person 。 我希望有一个表格可以在这儿创build条例草案及其子女在一个页面上收到全部费用

在页面上呈现适当的字段(尽pipe没有Person的下拉菜单),提交成功。 但是,没有一个孩子的会费保存到数据库,并在服务器日志中引发错误:

不允许的参数:dues_attributes

Rails 4中是否有过某种变化,或者我完全错过了某些东西。

在错误之前,日志显示这个:

Started POST "/bills" for 127.0.0.1 at 2013-04-10 00:16:37 -0700 Processing by BillsController#create as HTML<br> Parameters: {"utf8"=>"✓", "authenticity_token"=>"ipxBOLOjx68fwvfmsMG3FecV/q/hPqUHsluBCPN2BeU=", "bill"=>{"company"=>"Comcast", "month"=>"April ", "year"=>"2013", "dues_attributes"=>{ "0"=>{"amount"=>"30", "person_id"=>"1"}, "1"=>{"amount"=>"30", "person_id"=>"2"}, "2"=>{"amount"=>"30", "person_id"=>"3"}}}, "commit"=>"Create Bill"} 

相关代码列在下面

due.rb

 class Due < ActiveRecord::Base belongs_to :person belongs_to :bill end 

bill.rb

 class Bill < ActiveRecord::Base has_many :dues, :dependent => :destroy accepts_nested_attributes_for :dues, :allow_destroy => true end 

bills_controller.rb

  # GET /bills/new def new @bill = Bill.new 3.times { @bill.dues.build } end 

票据/ _form.html.erb

  <%= form_for(@bill) do |f| %> <div class="field"> <%= f.label :company %><br /> <%= f.text_field :company %> </div> <div class="field"> <%= f.label :month %><br /> <%= f.text_field :month %> </div> <div class="field"> <%= f.label :year %><br /> <%= f.number_field :year %> </div> <div class="actions"> <%= f.submit %> </div> <%= f.fields_for :dues do |builder| %> <%= render 'due_fields', :f => builder %> <% end %> <% end %> 

票据/ _due_fields.html.erb

 <div> <%= f.label :amount, "Amount" %> <%= f.text_field :amount %> <br> <%= f.label :person_id, "Renter" %> <%= f.text_field :person_id %> </div> 

更新到bills_controller.rb:这工作!

 def bill_params params.require(:bill).permit(:company, :month, :year, dues_attributes: [:amount, :person_id]) end 

似乎属性保护的处理发生了变化,现在您必须在控制器(而不是模型中的attr_accessible)中添加白名单,因为之前的可选gem strong_parameters成为了Rails Core的一部分。

这应该看起来像这样:

 class PeopleController < ActionController::Base def create Person.create(person_params) end private def person_params params.require(:person).permit(:name, :age) end end 

所以params.require(:model).permit(:fields)将被使用

和嵌套属性的东西

 params.require(:person).permit(:name, :age, pets_attributes: [:id, :name, :category]) 

一些更多的细节可以在Ruby边缘API文档和github或这里的 strong_parameters中 find

从文档

 To whitelist an entire hash of parameters, the permit! method can be used params.require(:log_entry).permit! 

嵌套属性是散列的forms。 在我的应用程序中,我有一个Question.rb模型接受Answer.rb模型的嵌套属性(其中用户为他创build的问题创build答案选项)。 在questions_controller中,我这样做

  def question_params params.require(:question).permit! end 

问题哈希中的所有内容都是允许的,包括嵌套的答案属性。 如果嵌套的属性是数组的forms,这也适用。

话虽如此,我不知道这种方法是否存在安全问题,因为它基本上允许在散列内部的任何内容,而不是明确地指定它是什么,这似乎与强参数的目的相反。

或者你可以简单地使用

 def question_params params.require(:question).permit(team_ids: []) end 

实际上有一种方法可以将所有嵌套的参数白名单。

 params.require(:widget).permit(:name, :description).tap do |whitelisted| whitelisted[:position] = params[:widget][:position] whitelisted[:properties] = params[:widget][:properties] end 

这种方法比其他解决scheme有优势。 它允许允许深嵌套的参数。

而其他解决scheme如:

 params.require(:person).permit(:name, :age, pets_attributes: [:id, :name, :category]) 

别。


资源:

https://github.com/rails/rails/issues/9454#issuecomment-14167664

今天我遇到了同样的问题,同时在rails 4上工作时,通过将fields_for的结构设置为:

 <%= f.select :tag_ids, Tag.all.collect {|t| [t.name, t.id]}, {}, :multiple => true %> 

然后在我的控制器中,我有很强的参数:

 private def post_params params.require(:post).permit(:id, :title, :content, :publish, tag_ids: []) end 

所有的作品!

如果使用JSONB字段,则必须使用.to_json(ROR)将其转换为JSON。