Railscast 196-197:Nested Model Form に示されているような状況になっています。しかし、私はこのアプローチと強力なパラメーターとの間に衝突を経験しました。フォームを通じて割り当て可能にしたくないので、ユーザーが子レコードを所有していない親レコードに関連付けるのを防ぐため、子オブジェクトの親レコードIDフィールドにデータを入力する良い方法がわかりません。 )。私は解決策を持っていますが(以下のコードを参照)、これは一種のことのように思われますRailsは私のために賢くて簡単な方法を持っているかもしれません。
これがコードです...
Has_many子オブジェクト(質問と呼ぶ)の親オブジェクト(Surveyと呼びます)があります。
# 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
ユーザーが調査とその調査に関する質問を同時に作成できるフォームがあります(簡単にするために、以下のコードでは調査に質問のみがあるかのように扱います)。
# 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 %>
問題はコントローラーです。強力なパラメーターを使用して質問レコードのsurvey_idフィールドを保護したいのですが、survey_idは必須フィールドであるため、そうすると質問は検証に合格しません。
# 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
この問題を解決するために私が考えることができる唯一の方法は、このように調査とは別に質問を作成することです:
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ベータ1、Ruby 2)
[〜#〜]更新[〜#〜]
おそらく、この問題を処理する最良の方法は、 このCode Climateブログの投稿 で提案されている「フォームオブジェクト」を除外することです。私は他の観点に興味があるので、私は質問を開いたままにします
したがって、実行中の問題は、子オブジェクトが検証に合格しないことですよね?子オブジェクトが親と同時に作成された場合、子オブジェクトは検証に合格するために親のIDを認識できなかった可能性があります。これはtrueです。
これがその問題を解決する方法です。次のようにモデルを変更します。
# app/models/survey.rb
class Survey
belongs_to :user
has_many :questions, :inverse_of => :survey
accepts_nested_attributes_for :questions
end
# app/models/question.rb
class Question
validates :survey, :presence => true
belongs_to :survey
end
ここでの違いは:inverse_of
アソシエーションに渡されるhas_many
であり、質問は:survey
ではなく:survey_id
のみで検証されるようになりました。
:inverse_of
は、関連付けを使用して子オブジェクトが作成または構築されるときに、それを作成した親への後方参照も受け取るようにします。これは自動的に発生するはずのように見えますが、このオプションを指定しない限り、残念ながら発生しません。
:survey
ではなく:survey_id
で検証することは、妥協のようなものです。検証では、survey_idフィールドに空白でないものが存在するかどうかを確認するだけではなくなりました。親オブジェクトの存在の関連を実際にチェックするようになりました。この場合、:inverse_of
が原因で役立つことがわかりますが、検証するために、実際にはIDを使用してデータベースから関連付けをロードする必要があります。これは、データベース内の何にも一致しないIDは検証に合格しないことも意味します。
お役に立てば幸いです。