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 %>

Вы должны сделать то же самое для ответов.