CoolNestedForms

Gem Version

Add Nested Forms to your Forms. Currently tested with a depth of 2. For example a Form can add an Item and this Item can add a sub Item. It can probably support longer nests but I haven't tested it yet.

By the way, this is intended to simplify adding the javascript required to add form_field dynamically while following form builder conventions. What that means is that there is some work to be done in the form of configuring models and controllers and adding a couple of views.

Installation

Add this line to your application's Gemfile:

gem 'cool_nested_forms'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install cool_nested_forms

Then require the javascript in your app/assets/javascripts/application.js

//= require cool_nested_forms

Usage Example

For this example I will use Job and Task models

Preparing your models

Job Model

class Job < ActiveRecord::Base
  has_many :tasks, :dependent => :destroy
  # :name is required - User your own required field here
  accepts_nested_attributes_for :tasks, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
end

Task Model

class Task < ActiveRecord::Base
  belongs_to :job
end

Preparing the Job Controller

class JobsController < ApplicationController

  # other code #

  def job_params
    # :id and :_destroy are required. Substitute name with your own fields
    params.require(:job).permit(:name,
      :tasks_attributes => [:id, :name, :_destroy])
  end
end

The view used to generate tasks

Due to laziness remove_child_button needs to be nested right under the containing div. this will be fixed in the next version. app/views/jobs/_task.html.rb

<div>
  <%= remove_child_button "Remove" %>
  <%= f.hidden_field :_destroy, :class => 'removable' %>

  <%= f.label :name %>
  <%= f.text_field :name %>
</div>

Adding functionality to the Job form

app/views/jobs/_form.html.erb

  <%= form_for(@job) do |f| %>


    <!-- your other job fields go here -->


    <!-- this generates a template for javascript -->  
    <%= new_fields_template f, :tasks, {object: Tasks.new, :template => "tasks_#{f.object.id}_fields"} %>  
    <!-- this generates a button that adds a task into    <div id="tasks_<%=f.object.id%>"> -->  
    <%= add_child_button "Add Task", :tasks, "tasks_#{f.object.id}", "tasks_#{f.object.id}", "<your-css-classes>" %>  

    <div id="tasks_<%=f.object.id%>">
      <%= f.fields_for :tasks, @job.tasks do |builder| %>
        <%= render "task", :f => builder %>
      <% end %>
    </div>

  <%end%>

After add/remove events

If you need to perform any other javascript actions after a child is added or removed, you can add a listener to these events

coolNestedForms.childAdded
coolNestedForms.childRemoved

Something like this

$(document).bind('coolNestedForms.childAdded', function(){
  // do something
});

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/cool_nested_forms. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.