У меня есть ситуация, подобная представленной в 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
Существует форма, позволяющая пользователям одновременно создавать опрос и вопросы об этом опросе (для простоты приведенный ниже код рассматривает опросы, как будто они имеют только вопрос):
# 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
Возможно, лучший способ справиться с этой проблемой состоит в том, чтобы разделить "объект формы", как предлагается в этом сообщении в блоге Code Climate. Я оставляю вопрос открытым, хотя, поскольку мне любопытно в других точках зрения