Nat*_*ace 34 ruby-on-rails strong-parameters
我的情况很像Railscast 196-197:嵌套模型表格.但是,我遇到了这种方法和强参数之间的冲突.我无法想出一个很好的方法来填充子对象上的父记录id字段,因为我不希望通过表单分配它(以防止用户将子记录与他们不拥有的父记录相关联) ).我有一个解决方案(见下面的代码),但这似乎是Rails可能有一个聪明,简单的方法为我做的事情.
这是代码......
有一个父对象(称之为Survey)有has_many子对象(称之为问题):
# 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
Run Code Online (Sandbox Code Playgroud)
有一个表单允许用户同时创建调查和该调查的问题(为简单起见,下面的代码将调查视为只有问题):
# 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 %>
Run Code Online (Sandbox Code Playgroud)
问题是控制器.我想通过强参数保护问题记录中的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
Run Code Online (Sandbox Code Playgroud)
我能想到解决这个问题的唯一方法是将这些问题与调查分开建立,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
(Rails 4 beta 1,Ruby 2)
UPDATE
处理此问题的最佳方法可能是按照Code Climate博客文章中的建议分解出"表单对象" .我打开这个问题,因为我对其他观点感到好奇
小智 71
所以你遇到的问题是子对象没有通过验证,对吧?当子对象与父对象同时创建时,子对象不可能知道其父对象的id以便通过验证,这是真的.
以下是解决该问题的方法.更改模型如下:
# 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
Run Code Online (Sandbox Code Playgroud)
这里的差异是:inverse_of传递给has_many关联,而问题现在验证:survey而不是:survey_id.
:inverse_of使它成为使用关联创建或构建子对象时,它还接收对创建它的父对象的反向引用.这似乎应该是自动发生的事情,但遗憾的是,除非您指定此选项.
验证:survey而不是on :survey_id是一种妥协.验证不再只是在survey_id字段中检查是否存在非空白; 它现在实际上检查关联是否存在父对象.在这种情况下,由于它有助于它:inverse_of,但在其他情况下,它实际上必须使用id从数据库加载关联以进行验证.这也意味着不匹配数据库中任何内容的ID将不会通过验证.
希望有所帮助.
| 归档时间: |
|
| 查看次数: |
10566 次 |
| 最近记录: |