Skip to content

Rails plugin to conveniently handle multiple models in a single form.

License

Notifications You must be signed in to change notification settings

fxposter/nested_form

 
 

Repository files navigation

Nested Form

<img src=“https://secure.travis-ci.org/fxposter/nested_form.png” />

This is a Rails gem for conveniently manage multiple nested models in a single form. It does so in an unobtrusive way through jQuery or Prototype.

This gem only works with Rails 3. See the rails2 branch for a plugin to work in Rails 2.

An example project showing how this works is available in the complex-nested-forms/nested_form branch.

Enhanced jQuery javascript template

Now you can override default behavior of inserting new subforms into your form (jQuery-only feature, sorry). For example:

window.nestedFormEvents.insertFields = function(content, assoc, link) {
  return $(link).closest('form').find(assoc + '_fields').append($(content));
}

Rails 3.1 support (with asset pipeline)

There’s a small fix for Rails 3.1 form handling. Also support of Rails 3.1 led me to huge refactor of specs setup (now using Helper specs from rspec-rails instead of custom implementation spec context).

Formtastic is supported only with Rails 3.0, Rails 3.1 integration is not available now.

Asset pipeline is supported. So you can use

//= require jquery_nested_form
// or
//= require prototype_nested_form

Setup

Add it to your Gemfile then run bundle to install it.

gem "nested_form"

Next run the generator to create the JavaScript file. This will automatically detect if you are using jQuery or Prototype.

rails g nested_form:install

Running the generator will add a file at public/javascripts/nested_form.js which should be included after the jQuery or Prototype framework.

<%= javascript_include_tag :defaults, "nested_form" %>

Usage

Imagine you have a Project model that has_many :tasks. To be able to use this gem, you’ll need to add accepts_nested_attributes_for :tasks to your Project model. If you don’t have the accepts_nested_attributes_for :tasks you’ll get a Missing Block Error.

This will create a tasks_attributes= method, so you may need to add it to the attr_accessible array. (attr_accessible :tasks_attributes)

Then use the nested_form_for helper method to enable the nesting.

<%= nested_form_for @project do |f| %>

You will then be able to use link_to_add and link_to_remove helper methods on the form builder in combination with fields_for to dynamically add/remove nested records.

<%= f.fields_for :tasks do |task_form| %>
  <%= task_form.text_field :name %>
  <%= task_form.link_to_remove "Remove this task" %>
<% end %>
<p><%= f.link_to_add "Add a task", :tasks %></p>

By default fields_for inside nested_form_for will add <div class=“fields”> wrapper for every nested object. Sometimes you need not the <div>, but the <tr> (if you insert rows into table). Now you can specify wrapping tag by providing :wrapper_tag => 'tr' option (by default it is ‘div’):

<table>
  <%= f.fields_for :tasks, :wrapper_tag => 'tr' do |task_form| %>
    <td>
      <%= task_form.hidden_field :id %>
      <%= task_form.text_field :name %>
      <%= task_form.link_to_remove "Remove this task" %>
    </td>
  <% end %>
</table>
<p><%= f.link_to_add "Add a task", :tasks %></p>

You should specify id field, cause form_for will insert it between <td>-s and this is not pretty good.

Also, you can specify :wrapper_class, which will be added “fields” class in wrapper element:

<%= f.fields_for :tasks, :wrapper_class => 'task' do |task_form| %>
  <%= task_form.text_field :name %>
  <%= task_form.link_to_remove "Remove this task" %>
<% end %>
<p><%= f.link_to_add "Add a task", :tasks %></p>

SimpleForm and Formtastic Support

Use simple_nested_form_for or semantic_nested_form_for for SimpleForm and Formtastic support respectively. This is feature is not yet in a Gem release but is in the Git repo.

Partials

It is often desirable to move the nested fields into a partial to keep things organized. If you don’t supply a block to fields_for it will look for a partial and use that.

<%= f.fields_for :tasks %>

In this case it will look for a partial called “task_fields” and pass the form builder as an f variable to it.

Events

If you are using jQuery, nested:fieldAdded and nested:fieldRemoved events are triggered on the form element after adding and removing fields.

Special Thanks

This gem was originally based on the solution by Tim Riley in his complex-form-examples fork.

Thank you Andrew Manshin for the Rails 3 transition, Andrea Singh for converting to a gem and Peter Giacomo Lombardo for Prototype support.

Andrea also wrote a great blog post on the internal workings of this gem.

Thanks Pavel Forkert for the SimpleForm and Formtastic support.

About

Rails plugin to conveniently handle multiple models in a single form.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Ruby 98.1%
  • JavaScript 1.9%