我的情况很像Railscast 196-197: Nested Model Form年前的情况.然而,我遇到了这种方法和强参数之间的冲突.我想不出一个好方法来填充子对象上的父记录id字段,因为我不希望通过表单分配该字段(以防止用户将子记录关联到他们不拥有的父记录).我有一个解决方案(见下面的代码),但这似乎是Rails可能为我提供的一种聪明、简单的方法.
这是密码...
有一个父对象(称为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 beta 1,Ruby 2)
UPDATE
也许处理这个问题的最佳方法是按照this Code Climate blog post中的建议,计算出一个"Form object".不过,由于我对其他观点很好奇,所以我将这个问题留待讨论