11

I cannot seem to get nested attributes to save to the database. I am using Rails 4.

Here are my models :

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

Here is the controller:

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

Finally, here is the form itself. I have tried using both f.fields_for and 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 %>

The survey saves fine to the database, put the questions and answers will not. I've looked at every resource I could find and it seems like I am doing this correctly, so it's really driving me crazy.

This example is just a quick scaffold so I had some code to paste in, but I can't seem to get it to work anywhere else.

edit: changing my new action to something like this:

def new
  @survey = Survey.new
  @survey.questions.build
end

WORKED!

SEE TEEGS ANSWER FOR SOLUTION TO THIS

Here is the new form I am using, still only saving the survey name

  <%= 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 %>
2
  • Have you tried using build to create empty relations on your new action in the controller? Commented Feb 11, 2014 at 20:01
  • @rlecaro2 I tried changing my new action to this: ` def new @survey = Survey.new @survey.questions.build end` and it still did not work Commented Feb 11, 2014 at 20:13

3 Answers 3

7

Looks like you're using the wrong form builder object. Change the question section to something like this:

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

Originally you were using the f form builder in the line f.fields_for :answers..., however given your model code, since it is a Question that accepts_nested_attributes_for an Answer, we simply exchange the form builder object for the one used for the question section.

Note: I changed the names of the builder objects for clarity.

Update

In order to build a deeply nested relationship like this, you will have to loop through your "built" association (questions in this case), and invoke build again on its has_many association. So going off of gabrielhilal's answer, you would do this:

def new
  @survey = Survey.new
  @survey.questions.build
  @survey.questions.each do |question|
      question.answers.build
  end
end

Note that in your case, since you are explicitly creating only one question, you can technically do this instead (instead of the loop):

@survey.questions.first.answers.build

Disclaimer: If there is a cleaner, more Rails-y, way to do this, I am sadly unaware of it.

Sign up to request clarification or add additional context in comments.

4 Comments

Woah, not sure how I missed that. However, after fixing it, I am still having the same issue. This is insanely puzzling.
@Michael Does gabrielhilal's answer help you at all? I forgot about the .build part. That may make a difference.
yes it did! Fixing the form and adding the @survey.questions.build got the questions to save. I just need to figure out how to build the answers as well. I tried adding this to my model : has_many :answers, through: :questions and this to my controller def new @survey = Survey.new @survey.questions.build @survey.answers.build end however the answers field is not showing up.
yes that worked! I don't know why I didn't think of that. Thank you so much!
4

In your controller you have questions_id:

def survey_params
  params.require(:survey).permit(:name, 
    questions_attributes: [
      :content, :id, :survey_id, 
      answers_attributes: [:content, :id, :questions_id]
    ]
  )
end

Is that a typo? Also try setting action_on_unpermitted_parameters to :raise in you development.rb to see if there is any attribute that you' re missing in your survey_params method.

# In case of unpermitted parameters in the controller raise error.
config.action_controller.action_on_unpermitted_parameters = :raise

2 Comments

It was a typo. I tried adding that setting to my development.rb and I am no errors are being raised when I save the survey.
Took me two an a half hours with my own similar problem before I saw this post. All I needed to do was put my answers_attributes[] inside my questions_attributes[]. You sir, are wonderful.
3

You must change your new action to include @survey.questions.build:

def new
  @survey = Survey.new
  @survey.questions.build
end

But your form is wrong as well. Change the question to questions

 <%= f.fields_for :questions do |builder| %> #questions
   <%= builder.label :content %>
   <%= builder.text_area :content %>

You must do the same thing for answers.

1 Comment

This plus a combination of the stuff above I got the questions to save! Now how can get answers to build? I tried changing the relationship on survey to has_many :answers, through: questions and adding @survey.answers.build, but the form is not displaying for answers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.