#196 Nested Model Form (revised)
Handling multiple models in a single form is easy with accepts_nested_attributes_for. Here you will also learn how to add and remove nested records through JavaScript.
- Download:
- source codeProject Files in Zip (104 KB)
- mp4Full Size H.264 Video (22 MB)
- m4vSmaller H.264 Video (12 MB)
- webmFull Size VP8 Video (15.4 MB)
- ogvFull Size Theora Video (26.4 MB)
Resources
models/survey.rb
class Survey < ActiveRecord::Base attr_accessible :name, :questions_attributes has_many :questions accepts_nested_attributes_for :questions, allow_destroy: true end
models/question.rb
class Question < ActiveRecord::Base attr_accessible :content, :survey_id, :answers_attributes belongs_to :survey has_many :answers accepts_nested_attributes_for :answers, allow_destroy: true end
views/surveys/_form.html.erb
<%= f.fields_for :questions do |builder| %> <%= render 'question_fields', f: builder %> <% end %> <%= link_to_add_fields "Add Question", f, :questions %>
views/surveys/_question_fields.html.erb
<fieldset> <%= f.label :content, "Question" %><br /> <%= f.text_area :content %><br /> <%= f.check_box :_destroy %> <%= f.label :_destroy, "Remove Question" %> <%= f.fields_for :answers do |builder| %> <%= render 'answer_fields', f: builder %> <% end %> <%= link_to_add_fields "Add Answer", f, :answers %> </fieldset>
views/surveys/_answer_fields.html.erb
<fieldset> <%= f.label :content, "Answer" %> <%= f.text_field :content %> <%= f.hidden_field :_destroy %> <%= link_to "remove", '#', class: "remove_fields" %> </fieldset>
surveys.js.coffee
jQuery -> $('form').on 'click', '.remove_fields', (event) -> $(this).prev('input[type=hidden]').val('1') $(this).closest('fieldset').hide() event.preventDefault() $('form').on 'click', '.add_fields', (event) -> time = new Date().getTime() regexp = new RegExp($(this).data('id'), 'g') $(this).before($(this).data('fields').replace(regexp, time)) event.preventDefault()
application_helper.rb
module ApplicationHelper def link_to_add_fields(name, f, association) new_object = f.object.send(association).klass.new 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