web-dev-qa-db-fra.com

Paramètres non autorisés d'attributs imbriqués

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?

126
jcanipar

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

180
thorsten müller

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.

20
Leahcim

ou vous pouvez simplement utiliser

def question_params

  params.require(:question).permit(team_ids: [])

end
20
Amit Agarwal

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

11

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!

3
Kingsley Ijomah

Si vous utilisez un champ JSONB, vous devez le convertir en JSON avec .to_json (ROR).

1
Wouter Schoofs