2013-04-10 18 views
111

Ich bin neu in RoR, aber ich habe entschieden, dass ich auch auf 4 lernen kann. Dies kann oder auch nicht eine gute Idee sein. Ich versuche, ein Formular mit geschachtelten Attributen zu erstellen, und ich kämpfe.Schienen 4 verschachtelte Attribute unerlaubte Parameter

Ich habe diese Railscast http://railscasts.com/episodes/196-nested-model-form-part-1 angeschaut und ich versuche, eine ähnliche Situation auf eigene Faust neu zu erstellen.

Ich habe eine Bill Objekt, das viele Due Objekte hat. Das Objekt Due gehört ebenfalls zu einer Person. Ich möchte ein Formular, wo ich die Bill und ihre Kinder Beiträge alle in einer Seite erstellen kann.

Die richtigen Felder werden auf der Seite gerendert (allerdings ohne ein Dropdown für Person) und das Senden ist erfolgreich. Doch keines der Kinder Beiträge werden in der Datenbank gespeichert und ein Fehler im Serverprotokoll geworfen:

Unpermitted parameters: dues_attributes

Gab es irgendeine Art von Veränderung in Rails 4, oder bin ich gerade etwas völlig fehlt.

Kurz vor dem Fehler, das Protokoll zeigt dies:

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



Relevante Code wird unter

aufgeführt

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 


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


Rechnungen /_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: Das funktioniert!

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

Fix auf Formatierung konvertieren: params.require (: bill).permit (: Firma,: Monat,: Jahr,: dues_attributes => [: Betrag,: Person_ID]) –

Antwort

163

scheint, gibt es eine Änderung in der Handhabung von Attributschutz und jetzt müssen Sie die weiße Liste params in der Steuerung (statt attr_accessible im Modell), weil die ehemaligen optional gem strong_parameters Teil des Rails-Core wurden.

Das ist etwas sollte wie folgt aussehen:

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

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

So params.require(:model).permit(:fields)

wie

und für verschachtelte Attribute etwas verwendet werden würde

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

Einige weitere Details in der Ruby edge API docs gefunden werden kann und strong_parameters on github oder here

+1

Ich habe meinen BillController so geändert: 'def bill_params params.require (: bill) .permit (: Unternehmen,: Monat: Jahr: dues_attributes [: Menge,: person_id]) end' ich diesen Fehler jetzt bin immer: ** keine implizite Umwandlung von Symbol in Integer ** – jcanipar

+2

nun, es hilft, Setzen Sie den Doppelpunkt an die richtige Stelle ... Dies ist genau das, was getan werden muss. Danke @ thorsten-muller! – jcanipar

+81

VERGESSEN SIE NICHT DIE ID !!!! 'pets_attributes: [: ID,: Name,: Kategorie]' Andernfalls, wenn Sie bearbeiten, wird jedes Haustier wieder erstellt. – Arcolye

18

der Dokumenten

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

params.require(:log_entry).permit! 

Nested Attribute sind in der Form einer Hash. In meiner App habe ich ein Question.rb-Modell akzeptiert verschachtelte Attribute für ein Answer.rb-Modell (wo der Benutzer Antwortmöglichkeiten für eine Frage erstellt, die er erstellt). Im questions_controller, mache ich das

def question_params 

     params.require(:question).permit! 

    end 

Alles in der Frage Hash erlaubt ist, einschließlich der verschachtelten Antwort Attribute. Dies funktioniert auch, wenn die verschachtelten Attribute in Form eines Arrays vorliegen.

Ich frage mich, ob es Sicherheitsbedenken bei diesem Ansatz gibt, weil es grundsätzlich alles erlaubt, was innerhalb des Hash ist, ohne genau anzugeben, was es ist, was dem Zweck der starken Parameter widerspricht.

+0

Awesome, ich kann einen Range-Parameter nicht explizit zulassen, das spart mir einige Stunden. –

+2

Ja, mit .permit! wird normalerweise als potenzielles Sicherheitsproblem angesehen. Sie würden es nur wirklich benutzen wollen, wenn der Benutzer ein Administrator ist, aber selbst dann würde ich vorsichtig sein. – 8bithero

+6

Meine verschachtelten Attribute sind auch in einem Array. Ist '.permit!' Die einzige Option? Ich kann es nicht mit allen erlaubten Modellattributen arbeiten lassen, weil es auf dem Array drosselt. –

16

oder Sie können einfach

def question_params 

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

end 
+0

danke, ich kann Params, die jetzt Array akzeptieren –

10

Eigentlich gibt es verwenden eine Möglichkeit, nur weiß-Liste alle verschachtelten Parameter.

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

Diese Methode hat einen Vorteil gegenüber anderen Lösungen. Es erlaubt tief verschachtelte Parameter zu erlauben.

Während andere Lösungen wie:

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

Nicht.


Quelle:

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

3

Heute habe ich auf dieses gleiche Problem kam, während der Arbeit an Schienen 4, konnte ich es durch Strukturierung meine fields_for wie zum Laufen bringen:

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

Dann in meinem Controller habe ich meine starken params als:

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

Alles funktioniert!

+0

Hallo danke @KingsleyIjomah - was, wenn Sie bestimmte Attribute der Kinder auflisten wollen? – BKSpurgeon

1

Wenn Sie ein JSONB Feld verwenden, müssen Sie es zu JSON mit .to_json (ROR)

Verwandte Themen