A demonstration of the nested_fields engine.
A book has 0 or 1 covers (has_one
).
A book has many chapters.
A chapter has many pages which are ordered by its number
column.
This example uses the nestedSortable jQuery UI plugin for ordering of pages. Just drag-and-drop within the form.
book.rb
has_one :cover has_many :chapters accepts_nested_attributes_for :chapters, :allow_destroy => true accepts_nested_attributes_for :cover, :allow_destroy => true
chapter.rb
belongs_to :book has_many :pages, :order => :number accepts_nested_attributes_for :pages, :allow_destroy => true
cover.rb
belongs_to :book
page.rb
belongs_to :chapter
layouts/application.rb
<script src="http://www.google.com/jsapi" type="text/javascript"></script> <script type="text/javascript"> google.load('jquery', '1.5'); google.load('jqueryui', '1.8.9'); </script> <%= javascript_include_tag :defaults, 'nested_fields' %>
books/_form.html.erb
<%= f.label :title %><br /> <%= f.text_field :title %> <%= nested_fields_for f, :cover %> <%= nested_fields_for f, :chapters %>
chapters/_fields.html.erb
<%= f.label :name %><br /> <%= f.text_field :name %> <%= nested_fields_for f, :pages, :positioned_by => :number %>
pages/_fields.html.erb
<%= f.label :text %><br /> <%= f.text_area :text, :rows => 3 %> <%= f.hidden_field :number %>
application.js
$(document).ready(function() { $('fieldset.positioned').trigger('nested_fields_changed'); }); $('fieldset.positioned').live('nested_fields_changed', function() { var pos_fld = this.getAttribute('data-positioned-by'); repositionNestedFields(this, pos_fld); if (!$(this).hasClass('ui-sortable')) { $(this).sortable({update: function() { repositionNestedFields(this, pos_fld); }}); } });