Rails 4 вложенные атрибуты не сохраняются
Я не могу получить вложенные атрибуты для сохранения в базе данных. Я использую Rails 4.
Вот мои модели:
class Answer < ActiveRecord::Base
belongs_to :question
end
class Question < ActiveRecord::Base
has_many :answers
belongs_to :survey
accepts_nested_attributes_for :answers, allow_destroy: true
end
class Survey < ActiveRecord::Base
has_many :questions
validates_presence_of :name
accepts_nested_attributes_for :questions
end
Вот контроллер:
def create
@survey = Survey.new(survey_params)
respond_to do |format|
if @survey.save
format.html { redirect_to @survey, notice: 'Survey was successfully created.' }
format.json { render action: 'show', status: :created, location: @survey }
else
format.html { render action: 'new' }
format.json { render json: @survey.errors, status: :unprocessable_entity }
end
end
end
def survey_params
params.require(:survey).permit(:name, questions_attributes:[:content, :id, :survey_id,
answers_attributes:[:content, :id, :questions_id]
])
end
Наконец, вот сама форма. Я пробовал использовать как f.fields_for, так и just fields_for
<%= form_for(@survey) do |f| %>
<% if @survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% @survey.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for :question do |builder| %>
<%= builder.label :content %>
<%= builder.text_area :content %>
<%= f.fields_for :answer do |builder| %>
<%= builder.label :content, "Answer" %>
<%= builder.text_field :content %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Опрос хорошо сохраняется в базе данных, вопросы и ответы не будут отвечать. Я посмотрел на каждый ресурс, который мог найти, и кажется, что я делаю это правильно, так что это действительно сводит меня с ума.
Этот пример - просто быстрый эшафот, поэтому у меня был код для вставки, но я не могу заставить его работать где-нибудь еще.
изменить:
изменение моего нового действия на что-то вроде этого:
def new
@survey = Survey.new
@survey.questions.build
end
РАБОТАЛ!
ПОСМОТРЕТЬ TEEGS ОТВЕТ ДЛЯ РЕШЕНИЯ ЭТОГО
Вот новая форма, которую я использую, но сохраняю только название опроса
<%= f.fields_for :question do |question_builder| %>
<%= form_for(@survey) do |f| %>
<% if @survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% @survey.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for :question do |question_builder| %>
<%= question_builder.label :content %>
<%= question_builder.text_area :content %>
<%= question_builder.fields_for :answer do |answer_builder| %>
<%= answer_builder.label :content, "Answer" %>
<%= answer_builder.text_field :content %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Ответы
Ответ 1
Похоже, вы используете неправильный объект построителя формы. Измените раздел вопроса на что-то вроде этого:
<%= f.fields_for :question do |question_builder| %>
<%= question_builder.label :content %>
<%= question_builder.text_area :content %>
<%= question_builder.fields_for :answer do |answer_builder| %>
<%= answer_builder.label :content, "Answer" %>
<%= answer_builder.text_field :content %>
<% end %>
<% end %>
Первоначально вы использовали построитель форм f
в строке f.fields_for :answers...
, однако с учетом вашего кода модели, так как это Question
, что accepts_nested_attributes_for
a Answer
, мы просто обмениваем объект построителя форм для тот, который используется для раздела Question
.
Примечание. Я изменил имена объектов-конструкторов для ясности.
Обновление
Чтобы построить глубоко вложенные отношения, подобные этому, вам придется циклически выполнить свою "встроенную" ассоциацию (questions
в этом случае) и снова вызвать build
в своей ассоциации has_many
. Так что, отправляясь на габриельхильный ответ, вы сделали бы это:
def new
@survey = Survey.new
@survey.questions.build
@survey.questions.each do |question|
question.answers.build
end
end
Примечание, что в вашем случае, поскольку вы явно создаете только один вопрос, вы можете технически сделать это вместо этого (вместо цикла):
@survey.questions.first.answers.build
Отказ от ответственности: Если у вас есть более чистый, более Rails-y, способ сделать это, я, к сожалению, не знаю.
Ответ 2
В вашем контроллере есть questions_id
:
def survey_params
params.require(:survey).permit(:name,
questions_attributes: [
:content, :id, :survey_id,
answers_attributes: [:content, :id, :questions_id]
]
)
end
Это опечатка? Также попробуйте установить action_on_unpermitted_parameters
на :raise
в development.rb
, чтобы увидеть, есть ли какой-либо атрибут, который вам не хватает в методе survey_params
.
# In case of unpermitted parameters in the controller raise error.
config.action_controller.action_on_unpermitted_parameters = :raise
Ответ 3
Вы должны изменить действие new
, чтобы включить @survey.questions.build
:
def new
@survey = Survey.new
@survey.questions.build
end
Но ваша форма тоже неправильная. Измените question
на questions
<%= f.fields_for :questions do |builder| %> #questions
<%= builder.label :content %>
<%= builder.text_area :content %>
Вы должны сделать то же самое для ответов.