ruby on rails - rails - Atributos anidados parámetros no permitidos
unpermitted parameter rails 5 (6)
Tengo un objeto Bill
, que tiene muchos objetos Due
. El objeto Due
también pertenece a una Person
. Quiero un formulario que pueda crear el Bill
y sus hijos. Dues
todo en una sola página. Estoy intentando crear un formulario utilizando atributos anidados, similares a los de este Railscast .
El código relevante se detalla a continuación:
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
facturas / _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 %>
facturas / _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>
ACTUALIZACIÓN a bills_controller.rb ¡ Esto funciona!
def bill_params
params
.require(:bill)
.permit(:company, :month, :year, dues_attributes: [:amount, :person_id])
end
Los campos correctos se muestran en la página (aunque sin un menú desplegable para Person
todavía) y el envío se realiza correctamente. Sin embargo, ninguna de las cuotas de los hijos se guarda en la base de datos y se genera un error en el registro del servidor:
Unpermitted parameters: dues_attributes
Justo antes del error, el registro muestra esto:
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"}
Ha habido algún cambio en Rails 4?
De los documentos
To whitelist an entire hash of parameters, the permit! method can be used
params.require(:log_entry).permit!
Los atributos anidados tienen forma de hash. En mi aplicación, tengo un modelo Question.rb que acepta atributos anidados para un modelo Answer.rb (donde el usuario crea opciones de respuesta para una pregunta que crea). En el questions_controller, hago esto
def question_params
params.require(:question).permit!
end
Todo en el hash de pregunta está permitido, incluidos los atributos de respuesta anidados. Esto también funciona si los atributos anidados están en forma de una matriz.
Habiendo dicho eso, me pregunto si hay un problema de seguridad con este enfoque porque básicamente permite todo lo que está dentro del hash sin especificar exactamente qué es, lo que parece contrario al propósito de los parámetros potentes.
En realidad, hay una manera de simplemente listar todos los parámetros anidados.
params.require(:widget).permit(:name, :description).tap do |whitelisted|
whitelisted[:position] = params[:widget][:position]
whitelisted[:properties] = params[:widget][:properties]
end
Este método tiene una ventaja sobre otras soluciones. Permite permitir parámetros anidados profundos.
Mientras que otras soluciones como:
params.require(:person).permit(:name, :age, pets_attributes: [:id, :name, :category])
No lo hagas
Fuente:
https://github.com/rails/rails/issues/9454#issuecomment-14167664
Hoy me encontré con este mismo problema, mientras trabajaba en rails 4, pude hacerlo funcionar estructurando mis fields_for as:
<%= f.select :tag_ids, Tag.all.collect {|t| [t.name, t.id]}, {}, :multiple => true %>
Luego en mi controlador tengo mis params fuertes como:
private
def post_params
params.require(:post).permit(:id, :title, :content, :publish, tag_ids: [])
end
¡Todo funciona!
Parece que hay un cambio en el manejo de la protección de atributos y ahora debe incluir parámetros en la lista blanca en el controlador (en lugar de attr_accessible en el modelo) porque la antigua gema opcional strong_parameters se convirtió en parte del núcleo de Rails.
Esto debería verse más o menos así:
class PeopleController < ActionController::Base
def create
Person.create(person_params)
end
private
def person_params
params.require(:person).permit(:name, :age)
end
end
Entonces se params.require(:model).permit(:fields)
y para atributos anidados algo así como
params.require(:person).permit(:name, :age, pets_attributes: [:id, :name, :category])
Se pueden encontrar más detalles en los documentos de la API de Ruby Edge y los parámetros strong_ en github o here
Si usa un campo JSONB, debe convertirlo a JSON con .to_json (ROR)
o simplemente puedes usar
def question_params
params.require(:question).permit(team_ids: [])
end