Attributi nidificati parametri non consentiti


127

Ho un Billoggetto, che ha molti Dueoggetti. L' Dueoggetto appartiene anche a Person. Voglio un modulo in grado di creare tutti i Billsuoi figli Duesin un'unica pagina. Sto cercando di creare un modulo utilizzando attributi nidificati, simili a quelli in questo Railscast .

Il codice pertinente è elencato di seguito:

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

Conto / _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 %>

Conto / _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>

AGGIORNAMENTO a bills_controller.rb Funziona!

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

I campi corretti vengono visualizzati sulla pagina (anche se ancora senza un menu a discesa Person) e l'invio ha esito positivo. Tuttavia, nessuna delle quote secondarie viene salvata nel database e viene generato un errore nel registro del server:

Unpermitted parameters: dues_attributes

Poco prima dell'errore, il registro mostra questo:

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"}

C'è stato qualche cambiamento in Rails 4?


5
Correzione della formattazione: params.require (: bill) .permit (: company,: month,: year,: dues_attributes => [: amount,: person_id])
Andy Copley,

Risposte:


187

Sembra che ci sia un cambiamento nella gestione della protezione degli attributi e ora è necessario autorizzare i parametri nel controller (anziché attr_accessible nel modello) perché l'ex gem opzionale strong_parameters è diventato parte del Rails Core.

Questo dovrebbe assomigliare a questo:

class PeopleController < ActionController::Base
  def create
    Person.create(person_params)
  end

private
  def person_params
    params.require(:person).permit(:name, :age)
  end
end

Quindi params.require(:model).permit(:fields)sarebbe usato

e per gli attributi nidificati qualcosa del genere

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

Alcuni ulteriori dettagli sono disponibili nei documenti API di Ruby edge e strong_parameters su github o qui


1
Ho cambiato il mio BillController in questo modo: def bill_params params.require(:bill).permit(:company, :month, :year, :dues_attributes[:amount, :person_id]) end sto ricevendo questo errore: nessuna conversione implicita di Symbol in Integer
jcanipar

2
Bene, aiuta a mettere i due punti nel posto giusto ... Questo è esattamente ciò che doveva essere fatto. Grazie @ thorsten-muller!
jcanipar,

88
NON DIMENTICARE L'ID !!!! pets_attributes: [:id, :name, :category]Altrimenti, quando modifichi, ogni animale verrà creato di nuovo.
Arcolye,

8
Devi farlo Person.create(person_params)o non chiamerà il metodo. Invece otterrai ActiveModel::ForbiddenAttributesError.
Andorov,

16
Inoltre, se si desidera distruggere gli elementi dal modulo, è necessario anche autorizzare il :_destroyparametro nascosto . vale a direpets_attributes: [:id, :name, :category, :_destroy]
Pathogen

21

Dai documenti

To whitelist an entire hash of parameters, the permit! method can be used

params.require(:log_entry).permit!

Gli attributi nidificati hanno la forma di un hash. Nella mia app, ho un modello Question.rb che accetta gli attributi nidificati per un modello Answer.rb (in cui l'utente crea le opzioni di risposta per una domanda che crea). Nel question_controller, lo faccio

  def question_params

      params.require(:question).permit!

  end

È consentito tutto nell'hash della domanda, inclusi gli attributi di risposta nidificati. Questo funziona anche se gli attributi nidificati sono nella forma di un array.

Detto questo, mi chiedo se ci sia un problema di sicurezza con questo approccio perché in pratica consente tutto ciò che è all'interno dell'hash senza specificare esattamente cosa sia, il che sembra contrario allo scopo di parametri forti.


Fantastico, non posso autorizzare esplicitamente un parametro di intervallo, questo mi fa risparmiare alcune ore.
Bartek Skwira,

3
Sì, usando .permit! è generalmente visto come un potenziale problema di sicurezza. Vorresti davvero usarlo solo se l'utente è un amministratore, ma anche allora sarei diffidente nei confronti del suo utilizzo.
8bithero,

6
Anche i miei attributi nidificati sono in un array. È .permit!l'unica opzione? Non riesco a farlo funzionare anche con tutti gli attributi del modello consentiti perché soffoca sull'array.
Clifton Labrum,

20

o puoi semplicemente usare

def question_params

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

end

12

In realtà c'è un modo per mettere in lista bianca tutti i parametri nidificati.

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

Questo metodo ha un vantaggio rispetto ad altre soluzioni. Permette di consentire parametri nidificati in profondità.

Mentre altre soluzioni come:

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

Non farlo.


Fonte:

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


3

Oggi ho riscontrato questo stesso problema, mentre lavoravo su rotaie 4, sono stato in grado di farlo funzionare strutturando i miei campi_per come:

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

Quindi nel mio controller ho i miei parametri forti come:

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

Funziona tutto!


ciao grazie @KingsleyIjomah - cosa succede se si desidera inserire nella lista bianca gli attributi specifici dei bambini?
BKSpurgeon,

1

Se si utilizza un campo JSONB, è necessario convertirlo in JSON con .to_json (ROR)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.