diff options
author | Eloy Duran <eloy.de.enige@gmail.com> | 2009-03-15 00:40:34 +0100 |
---|---|---|
committer | Eloy Duran <eloy.de.enige@gmail.com> | 2009-03-15 00:40:59 +0100 |
commit | 0e12b554c9601d0402ea3d5038f72fcace5bfb31 (patch) | |
tree | b1d303dcd4271f6bce869f7abe0334ebccbdbd54 /railties/guides/source | |
parent | 952d1cc75aed26c79706447b8a76cf1f3f8c5890 (diff) | |
download | rails-0e12b554c9601d0402ea3d5038f72fcace5bfb31.tar.gz rails-0e12b554c9601d0402ea3d5038f72fcace5bfb31.tar.bz2 rails-0e12b554c9601d0402ea3d5038f72fcace5bfb31.zip |
Started on a Rails guide on nested model forms.
Diffstat (limited to 'railties/guides/source')
-rw-r--r-- | railties/guides/source/nested_model_forms.textile | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/railties/guides/source/nested_model_forms.textile b/railties/guides/source/nested_model_forms.textile new file mode 100644 index 0000000000..e975b97ea8 --- /dev/null +++ b/railties/guides/source/nested_model_forms.textile @@ -0,0 +1,177 @@ +h2. Rails nested model forms + +Creating a form for a model _and_ its associations can become quite tedious. Therefor Rails provides helpers to assist in dealing with the complexities of generating these forms _and_ the required CRUD operations to create, update, and destroy associations. + +In this guide you will: + +* do stuff + +endprologue. + +NOTE: This guide assumes the user knows how to use the "Rails form helpers":form_helpers.html in general. Also, it’s *not* an API reference. For a complete reference please visit "the Rails API documentation":http://api.rubyonrails.org/. + + +h3. Model setup + +To be able to use the nested model functionality in your forms, the model will need to support some basic operations. + +First of all, it needs to define a writer method for the attribute that corresponds to the association you are building a nested model form for. The +fields_for+ form helper will look for this method to decide whether or not a nested model form should be build. + +If the associated object is an array a form builder will be yielded for each object, else only a single form builder will be yielded. + +Consider a Person model with an associated Address. When asked to yield a nested FormBuilder for the +:address+ attribute, the +fields_for+ form helper will look for a method on the Person instance named +address_attributes=+. + +h4. ActiveRecord::Base model + +For an ActiveRecord::Base model and association this writer method is commonly defined with the +accepts_nested_attributes_for+ class method: + +h5. has_one + +<ruby> +class Person < ActiveRecord::Base + has_one :address + accepts_nested_attributes_for :address +end +</ruby> + +h5. belongs_to + +<ruby> +class Person < ActiveRecord::Base + belongs_to :firm + accepts_nested_attributes_for :firm +end +</ruby> + +h5. has_many / has_and_belongs_to_many + +<ruby> +class Person < ActiveRecord::Base + has_many :projects + accepts_nested_attributes_for :projects +end +</ruby> + +h4. Custom model + +As you might have inflected from this explanation, you _don’t_ necessarily need an ActiveRecord::Base model to use this functionality. The following examples are sufficient to enable the nested model form behaviour: + +h5. Single associated object + +<ruby> +class Person + def address + Address.new + end + + def address_attributes=(attributes) + # ... + end +end +</ruby> + +h5. Association collection + +<ruby> +class Person + def projects + [Project.new, Project.new] + end + + def projects_attributes=(attributes) + # ... + end +end +</ruby> + +NOTE: See (TODO) in the advanced section for more information on how to deal with the CRUD operations in your custom model. + +h3. Views + +h4. Controller code + +A nested model form will _only_ be build if the associated object(s) exist. This means that for a new model instance you would probably want to build the associated object(s) first. + +Consider the following typical RESTful controller which will prepare a new Person instance and its +address+ and +projects+ associations before rendering the +new+ template: + +<ruby> +class PeopleController < ActionController:Base + def new + @person = Person.new + @person.built_address + 2.times { @person.projects.build } + end + + def create + @person = Person.new(params[:person]) + if @person.save + # ... + end + end +end +</ruby> + +NOTE: Obviously the instantiation of the associated object(s) can become tedious and not DRY, so you might want to move that into the model itself. ActiveRecord::Base provides an +after_initialize+ callback which is a good way to refactor this. + +h4. Form code + +Now that you have a model instance, with the appropriate methods and associated object(s), you can start building the nested model form. + +h5. Standard form + +Start out with a regular RESTful form: + +<erb> +<% form_for @person do |f| %> + <%= f.text_field :name %> +<% end %> +</erb> + +This will generate the following html: + +<html> +<form action="/people" class="new_person" id="new_person" method="post"> + <input id="person_name" name="person[name]" size="30" type="text" /> +</form> +</html> + +h5. Nested form for a single associated object + +Now add a nested form for the +address+ association: + +<erb> +<% form_for @person do |f| %> + <%= f.text_field :name %> + + <% f.fields_for :address do |af| %> + <%= f.text_field :street %> + <% end %> +<% end %> +</erb> + +This generates: + +<html> +<form action="/people" class="new_person" id="new_person" method="post"> + <input id="person_name" name="person[name]" size="30" type="text" /> + + <input id="person_address_attributes_street" name="person[address_attributes][street]" size="30" type="text" /> +</form> +</html> + +Notice that +fields_for+ recognized the +address+ as an association for which a nested model form should be build by the way it has namespaced the +name+ attribute. + +When this form is posted the Rails parameter parser will construct a hash like the following: + +<ruby> +{ + "person" => { + "name" => "Eloy Duran", + "address_attributes" => { + "street" => "Nieuwe Prinsengracht" + } + } +} +</ruby> + +That’s it. The controller will simply pass this hash on to the model from the +create+ action. The model will then handle building the +address+ association for you and automatically be saved when the parent (+person+) is saved.
\ No newline at end of file |