Question

Hi I've gone though Railscast 196 & 197 and got everything working, however I have a question about extending the functionality.

At the end of Railscast 196 & 197 (http://railscasts.com/episodes/197-nested-model-form-part-2) Ryan adds a question and then adds answers individually. What I'm trying to implement is adding answers automatically when a question is added.

Here is the project code: http://railscasts.com/episodes/196-nested-model-form-revised (or an older version if you do not have a subscription: http://railscasts.com/episodes/197-nested-model-form-part-2)

There is a comment in the comments section that suggest that the line child_object = f.object.class.reflect_on_association(association).klass.reflect_on_association(child_association).klass.new be added to the helper to accomplish this, however when I implement this I get the error:

undefined method 'klass' for nil:NilClass

EDIT: To be clear, it's failing with this error when trying to build the child_object. The new_object will build and render correctly.

My Modified helper

def link_to_add_fields(name, f, association, container, child_association)
  new_object = f.object.class.reflect_on_association(association).klass.new
  child_object = f.object.class.reflect_on_association(association).klass.reflect_on_association(child_association).klass.new
  new_object.answers = child_object

  fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
    render(association.to_s + "/" + association.to_s.singularize + "_fields", :f => builder)
  end

  link_to name, "#", class: "add-fields", data: { container: "#{container}", association: "#{association}", content: "#{fields}" }
end

Call to helper

= form_for @survey, :html => { :multipart => true } do |f|
  %fieldset
    %legend
      Questions
    #questions.nested
      = f.fields_for :questions do |question|
        = render 'questions/question_fields', :f => question
    = link_to_add_fields "Add Question", f, :questions, "questions", :image
Was it helpful?

Solution

Ok, finally got this figured out!

Form

<%= form_for @survey do |f| %>
  <% if @survey.errors.any? %>
    <div class="error_messages">
      <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 :questions do |builder| %>
    <%= render 'question_fields', f: builder %>
  <% end %>
  <%= link_to_add_fields "Add Question", f, :questions, :answers %>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Helper

module ApplicationHelper
  def link_to_add_fields(name, f, association, child_association = nil)
    new_object = f.object.send(association).klass.new

    if child_association
      3.times{ new_object.send(child_association).build } #Builds 3 Answers
      #new_object.send(child_association).build #Builds 1 Answer
    end

    id = new_object.object_id

    fields = f.fields_for(association, new_object, child_index: id) do |builder|
      render(association.to_s.singularize + "_fields", f: builder)
    end

    link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
  end
end

The child_association = nil and

if child_association
  3.times{ new_object.send(child_association).build } #Builds 3 Answers
  #new_object.send(child_association).build #Builds 1 Answer
end

are there because adding new answers via the link also uses the same helper, but since answers doesn't accept any nested attributes it would fail. Adding the above allows you to use the same helper for both and stay DRY.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top