The Definitive Guide to accepts_nested_attributes_for a model in rails 3

by currentricity

accepts_nested_attributes_for is very useful when you want a single form to cater to multiple models. It gives you an easy way to include attributes from the associated tables and also to successfully save and delete objects.

Consider a scenario where ‘House’ has many ‘Rooms’  and has one ‘Address’. It also belongs to an ‘Owner’. Now suppose you want a single form for house which is able to present attributes for room[size], address[city,country] and user[fname,lname] and also is able to save it successfully. It entails the following steps.

1. In model house.rb

class House < ActiveRecord::Base
  belongs_to :owner
  has_one :address
  has_many :rooms
  accepts_nested_attributes_for :owner
  accepts_nested_attributes_for :address
  accepts_nested_attributes_for :rooms
end

2. In house_controller.rb you need to build the attributes. Notice the different methods used to build different associated models. It is a function of whether House has one or many of the other model. (Belongs to is a ‘one’ association). Also, I am only showing the parts which needs deviation from the general scaffolded code.

  def new
    @house = House.new
    @house.rooms.build
    @house.build_address
    @house.build_owner

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @house }
    end
  end

3. In view i.e. the house/_form.html.erb add the attributes

  <%= f.fields_for :address do |builder| %>

    <div class="field">
      <%= builder.label :city %><br />
      <%= builder.text_field :city %>
    </div>
  <% end -%>
  <%= f.fields_for :rooms do |builder| %>

    <div class="field">
      <%= builder.label :size %><br />
      <%= builder.number_field :size %>
    </div>
  <% end -%>

  <%= f.fields_for :owner do |builder| %>

    <div class="field">
      <%= builder.label :fname %><br />
      <%= builder.text_field :fname %>
    </div>
    <div class="field">
      <%= builder.label :lname %><br />
      <%= builder.text_field :lname %>
    </div>

  <% end -%>

4. Use

:allow_destroy => true

as a param to accepts_nested_attributes_for to be able to successfully delete.