Schienen — zum Auffüllen der id des übergeordneten Objekts verwenden von geschachtelten Attribute für untergeordnete Objekt und starken Parameter?
Habe ich eine situation ähnlich wie dargestellt in Railscast 196-197: Nested-Modell-Form. Allerdings habe ich festgestellt ein Konflikt zwischen diesem Ansatz und der starken Parameter. Ich kann nicht herausfinden, eine gute Möglichkeit zum Auffüllen des parent-record Feld-id für das untergeordnete Objekt, da ich nicht möchte, dass sein belegbar durch die form (zu verhindern, dass Benutzer zuordnen untergeordneten Datensätze zu übergeordneten Datensätze, die Sie nicht besitzen). Ich habe eine Lösung (siehe code unten), aber dies scheint die Art von Sache, die Schienen könnten mit einem cleveren, einfach Weg, dies zu tun für mich.
Hier ist der code...
Gibt es ein parent-Objekt (nennen wir es Umfrage), dass has_many untergeordneten Objekte (nennen wir Sie Fragen):
# app/models/survey.rb
class Survey
belongs_to :user
has_many :questions
accepts_nested_attributes_for :questions
end
# app/models/question.rb
class Question
validates :survey_id, :presence => true
belongs_to :survey
end
Gibt es ein Formular, das Benutzern erlaubt, um eine Umfrage zu erstellen und die Fragen, die auf die Umfrage zur gleichen Zeit (für die Einfachheit, den code unten Umfragen behandelt, als hätten Sie nur die Frage):
# app/views/surveys/edit.html.erb
<%= form_for @survey do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br />
<%= f.fields_for :questions do |builder| %>
<%= builder.label :content, "Question" %>
<%= builder.text_area :content, :rows => 3 %><br />
<% end %>
<%= f.submit "Submit" %>
<% end %>
Das problem ist der controller. Ich möchte zum Schutz der survey_id Feld auf die Frage, Datensatz über starke Parameter, aber dabei die Fragen, die don ' T-pass-Validierung, da die survey_id ist ein erforderliches Feld.
# app/controllers/surveys_controller.rb
class SurveysController
def edit
@survey = Survey.new
Survey.questions.build
end
def create
@survey = current_user.surveys.build(survey_params)
if @survey.save
redirect_to @survey
else
render :new
end
end
private
def survey_params
params.require(:survey).permit(:name, :questions_attributes => [:content])
end
end
Die einzige Möglichkeit die ich denken kann, um dieses problem zu lösen, ist das erstellen der Fragen getrennt von der Umfrage wie diese:
def create
@survey = current_user.surveys.build(survey_params)
if @survey.save
if params[:survey][:questions_attributes]
params[:survey][:questions_attributes].each_value do |q|
question_params = ActionController::Parameters.new(q)
@survey.questions.build(question_params.permit(:content))
end
end
redirect_to @survey
else
render :new
end
end
private
def survey_params
params.require(:survey).permit(:name)
end
(Rails 4 beta 1 Ruby 2)
UPDATE
Vielleicht der beste Weg, dieses problem zu behandeln, ist die Faktor, eine "Form Objekt", wie vorgeschlagen, in dieser Code Klima-blog-post. Ich lasse die Frage offen, obwohl, wie ich bin neugierig auf andere Sichtweisen
- haben Sie herausfinden, wie man dieses Problem beheben, mithilfe einer geschachtelten form?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Also das problem, das Sie laufen in ist, dass die untergeordneten Objekte nicht passieren Validierung, richtig? Wenn die Kind-Objekte erstellt werden, zur gleichen Zeit, als der Elternteil, der Kind-Objekte konnten nicht wissen, die id der Eltern, um die Gültigkeitsprüfung, es ist wahr.
Hier ist, wie können Sie das problem lösen. Ändern Sie Ihre Modelle wie folgt:
Die Unterschiede hier sind die
:inverse_of
an diehas_many
Verband, und dass die Frage nun überprüft, auf nur:survey
statt:survey_id
.:inverse_of
macht es so, dass, wenn ein Kind-Objekt erstellt wird oder erstellt mit dem Verein, es erhält auch eine zurück-Verweis auf den übergeordneten, die es geschaffen. Dies scheint wie etwas, das passieren sollte automagisch, aber es leider noch nicht, es sei denn, Sie geben diese option.Validierung auf
:survey
statt auf:survey_id
ist eine Art Kompromiss. Die Validierung ist nicht mehr einfach die Kontrolle für die Existenz von etwas nicht-leere in der survey_id Feld; es wird nun tatsächlich prüft der Verein für die Existenz eines übergeordneten Objekts. In diesem Fall ist es hilfreich bekannt durch:inverse_of
, in anderen Fällen aber wird es tatsächlich zum laden der Verein aus der Datenbank mit der id zu validieren. Dies bedeutet auch, dass die ids nicht übereinstimmen, nichts in der Datenbank wird nicht passieren Validierung.Hoffe, das hilft.
inverse_of
weil unsere Beziehung istpolymorphic
?