J'ai un objet Bill
, qui contient de nombreux objets Due
. L'objet Due
appartient également à un objet Person
. Je veux un formulaire qui puisse créer la Bill
et ses enfants Dues
sur une seule page. J'essaie de créer un formulaire en utilisant des attributs imbriqués, similaires à ceux de this Railscast .
Le code pertinent est répertorié ci-dessous:
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
bills/_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 %>
factures/_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>
UPDATE à bills_controller.rb Cela fonctionne!
def bill_params
params
.require(:bill)
.permit(:company, :month, :year, dues_attributes: [:amount, :person_id])
end
Les champs appropriés sont affichés sur la page (mais sans liste déroulante pour Person
encore) et l'envoi a abouti. Toutefois, aucune des cotisations des enfants n'est enregistrée dans la base de données et une erreur est générée dans le journal du serveur:
Unpermitted parameters: dues_attributes
Juste avant l'erreur, le journal affiche ceci:
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"}
Y a-t-il eu des changements dans Rails 4?
Il semble y avoir un changement dans la gestion de la protection d'attribut et vous devez maintenant ajouter des paramètres à la liste blanche dans le contrôleur (au lieu d'attr_accessible dans le modèle) car l'ancienne gem strong_parameters, en option, faisait désormais partie du noyau Rails.
Cela devrait ressembler à ceci:
class PeopleController < ActionController::Base
def create
Person.create(person_params)
end
private
def person_params
params.require(:person).permit(:name, :age)
end
end
Donc, params.require(:model).permit(:fields)
serait utilisé
et pour les attributs imbriqués quelque chose comme
params.require(:person).permit(:name, :age, pets_attributes: [:id, :name, :category])
Quelques détails supplémentaires sont disponibles dans les docs de l'API Ruby Edge et paramètres forts sur github ou ici
De la docs
To whitelist an entire hash of parameters, the permit! method can be used
params.require(:log_entry).permit!
Les attributs imbriqués se présentent sous la forme d'un hachage. Dans mon application, j'ai un modèle Question.rb qui accepte les attributs imbriqués pour un modèle Answer.rb (où l'utilisateur crée des choix de réponse pour une question qu'il crée). Dans le questions_controller, je le fais
def question_params
params.require(:question).permit!
end
Tout le contenu de la question est autorisé, y compris les attributs de réponse imbriqués. Cela fonctionne aussi si les attributs imbriqués sont sous la forme d'un tableau.
Cela dit, je me demande si cette approche pose un problème de sécurité, car elle autorise essentiellement tout ce qui se trouve à l'intérieur du hachage sans préciser ce qu'il en est, ce qui semble aller à l'encontre de l'objectif de paramètres forts.
ou vous pouvez simplement utiliser
def question_params
params.require(:question).permit(team_ids: [])
end
En fait, il existe un moyen de simplement mettre en liste blanche tous les paramètres imbriqués.
params.require(:widget).permit(:name, :description).tap do |whitelisted|
whitelisted[:position] = params[:widget][:position]
whitelisted[:properties] = params[:widget][:properties]
end
Cette méthode a un avantage sur les autres solutions. Il permet d'autoriser des paramètres imbriqués en profondeur.
Alors que d'autres solutions comme:
params.require(:person).permit(:name, :age, pets_attributes: [:id, :name, :category])
Ne pas.
La source:
https://github.com/Rails/rails/issues/9454#issuecomment-14167664
Aujourd'hui, je suis tombé sur le même problème. Tout en travaillant sur Rails 4, j'ai pu le faire fonctionner en structurant mes champs_pour:
<%= f.select :tag_ids, Tag.all.collect {|t| [t.name, t.id]}, {}, :multiple => true %>
Ensuite, dans mon contrôleur, j'ai mes paramètres puissants comme:
private
def post_params
params.require(:post).permit(:id, :title, :content, :publish, tag_ids: [])
end
Tout fonctionne!
Si vous utilisez un champ JSONB, vous devez le convertir en JSON avec .to_json (ROR).