# Render partials with nested attributes in another model

**URL:** <https://www.ruby-forum.com/t/render-partials-with-nested-attributes-in-another-model/177294>\
**Category:** Rails\
**Created:** [October 14, 2009, 4:33pm UTC](https://www.ruby-forum.com/t/render-partials-with-nested-attributes-in-another-model/177294 "2009-10-14T16:33:26Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ryan\_Tinsley](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/aeb1de/32.png) [@Ryan\_Tinsley](https://www.ruby-forum.com/u/Ryan_Tinsley)\
**Post date:** [October 14, 2009, 4:33pm UTC](https://www.ruby-forum.com/t/render-partials-with-nested-attributes-in-another-model/177294/1 "2009-10-14T16:33:26Z")

</div>

Hi everyone,

My previous question was posted  
here[http://groups.google.com/group/rubyonrails-talk/browse\_thread/thread/dddaeb075789d4b5](http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/dddaeb075789d4b5).  
I’m starting a new topic as the problems have shifted.

I have a rails application that models a house. There is a house model  
that  
has\_many rooms. A room has a house\_id and a name. I’ve also used the  
complex-form-examples to give room nested attributes of lights and  
small\_appliances. complex-form-examples uses RJS and partials to  
accomplish  
this.

There is a controller called calculator that is what users will use to  
access the application. When the submit button on calculator is pressed,  
it  
saves house information and redirects to an add\_rooms page (located in  
app/views/calculator/add\_rooms.html.erb) where the user can add rooms to  
the  
house. The add\_rooms page uses a partial from  
app/views/rooms/\_room\_form.html.erb. I can get this page to display by  
removing the add\_child\_link links. If I don’t remove them, I get this  
error:

```
Showing app/views/rooms/_room_form.html.erb where line #13 raised:

undefined method `reflect_on_association' for NilClass:Class

```

With add\_child\_link gone the page renders. However, when I click submit  
I  
get a new error message:

```
ActiveRecord::AssociationTypeMismatch in 

```

CalculatorController#add\_room

```
SmallAppliance(#49096610) expected, got Array(#1560620)

RAILS_ROOT: C:/Users/ryan/Downloads/react
Application Trace | Framework Trace | Full Trace

C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_proxy.rb:263:in

```

`raise_on_type_mismatch' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_collection.rb:320:in `replace’  
C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active\_record/associations/association\_collection.rb:320:in  
`each' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_collection.rb:320:in `replace’  
C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active\_record/associations.rb:1322:in  
`small_appliances=' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2744:in `send’  
C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active\_record/base.rb:2744:in  
`attributes=' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2740:in `each’  
C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active\_record/base.rb:2740:in  
`attributes=' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2438:in `initialize’  
C:/Users/ryan/Downloads/react/app/controllers/calculator\_controller.rb:31:in  
`new' C:/Users/ryan/Downloads/react/app/controllers/calculator_controller.rb:31:in `add\_room’

If I remove the small\_application part, the same thing happens for  
light. I  
think it has something to do with accepts\_nested\_attributes\_for in the  
room  
model. I need to get this page working so that rooms can be added to a  
house  
without using the scaffold built pages. Users won’t have access to  
those. I  
also need the house id to be saved as house\_id in the rooms table. Here  
is  
the code:

_app/models/room.rb_

```
class Room < ActiveRecord::Base
  belongs_to :house
  has_many :lights, :dependent => :destroy
  has_many :small_appliances, :dependent => :destroy
  validates_presence_of :name
  accepts_nested_attributes_for :lights, :reject_if => lambda {

```

|a| a.values.all?(&:blank?) }, :allow\_destroy =\> true  
accepts\_nested\_attributes\_for :small\_appliances, :reject\_if =\>  
lambda { |a| a.values.all?(&:blank?) }, :allow\_destroy =\> true  
end

_app/models/house.rb_

```
class House < ActiveRecord::Base
  has_many :rooms

  # validation code not included

  def add_room(room)
    rooms << room
  end

end

```

_app/controllers/calculator\_controller.rb_

```
class CalculatorController < ApplicationController
  def index
  end

  # save_house is called when submit is
  # pressed in app/views/calculator/index.html.erb
  def save_house
    @house = House.new(params[:house])
    respond_to do |format|
      if @house.save
        format.html { render :action => 'add_rooms', :id => @house }
        format.xml { render :xml => @house, :status => :created,

```

:location =\> @house }  
else  
format.html { render :action =\> ‘index’ }  
format.xml { render :xml =\> @house.errors, :status =\>  
:unprocessable\_entity }  
end  
end  
end

```
  def add_rooms
    @house = House.find(params[:id])
    @rooms = Room.find_by_house_id(@house.id)

  rescue ActiveRecord::RecordNotFound
    logger.error("Attempt to access invalid house #{params[:id]}")
    flash[:notice] = "You must create a house before adding rooms"
    redirect_to :action => 'index'
  end

  def add_room
    @house = House.find(params[:id])
    @room = Room.new(params[:room])

    respond_to do |format|
      if @room.save
        @house.add_room(@room)
        @house.save
        flash[:notice] = "Room \"#removed_email_address@domain.invalid}\" was successfully 

```

added."  
format.html { render :action =\> ‘add\_rooms’ }  
format.xml { render :xml =\> @room, :status =\> :created,  
:location =\> @room }  
else  
format.html { render :action =\> ‘add\_rooms’ }  
format.xml { render :xml =\> @room.errors, :status =\>  
:unprocessable\_entity }  
end  
end  
rescue ActiveRecord::RecordNotFound  
logger.error(“Attempt to access invalid house #{params[:id]}”)  
flash[:notice] = “You must create a house before adding a room”  
redirect\_to :action =\> ‘index’  
end

```
  def report
    flash[:notice] = nil
    @house = House.find(params[:id])
    @rooms = Room.find_by_house_id(@house.id)
  rescue ActiveRecord::RecordNotFound
    logger.error("Attempt to access invalid house #{params[:id]}")
    flash[:notice] = "You must create a house before generating a 

```

report"  
redirect\_to :action =\> ‘index’  
end

```
end

```

_app/views/calculator/add\_rooms.html.erb_  
&lt;div id=“addRooms”&gt;  
 &lt;p&gt;House id is  
&lt;%= @house.id %&gt;&lt;/p&gt;  
  
  
&lt;h3&gt;Your rooms:&lt;/h3&gt;  
 &lt;% if  
@house.rooms %&gt;  
 &lt;ul&gt;  
 &lt;% for room in  
@house.rooms %&gt;  
 &lt;li&gt;  
 &lt;%= h  
room.name%&gt; has &lt;%= h room.number\_of\_bulbs %&gt;  
  
&lt;%= h  
room.wattage\_of\_bulbs %&gt; watt bulbs, in use for  
 &lt;%= h  
room.usage\_hours %&gt; hours per day.  
 &lt;/li&gt;  
  
&lt;% end %&gt;  
 &lt;/ul&gt;  
 &lt;% else  
%&gt;  
 &lt;p&gt;You have not added any rooms  
yet&lt;/p&gt;  
 &lt;% end %&gt;  
  
 &lt;%=  
render  
:partial =&gt; ‘rooms/room\_form’ %&gt;  
  
 &lt;br  
/&gt;  
 &lt;%= button\_to “Continue to report”, :action  
=&gt;  
“report”, :id =&gt; @house %&gt;  
 &lt;/div&gt;

_app/views/rooms/\_room\_form.html.erb_

```
&amp;lt;% form_for :room, :url =&amp;gt; { :action =&amp;gt;

```

:add\_room, :id =&gt; @house } do |form| %&gt;  
&lt;%= form.error\_messages %&gt;  
&lt;p&gt;  
&lt;%= form.label :name %&gt;&lt;br /&gt;  
&lt;%= form.text\_field :name %&gt;  
&lt;/p&gt;

```
  &amp;lt;h3&amp;gt;Lights&amp;lt;/h3&amp;gt;
  &amp;lt;% form.fields_for :lights do |light_form| %&amp;gt;
    &amp;lt;%= render :partial =&amp;gt; 'rooms/light', :locals

```

=&gt; { :form =&gt; light\_form } %&gt;  
&lt;% end %&gt;  
&lt;p class=“addLink”&gt;&lt;%= add\_child\_link “[+]  
Add new light”, form, :lights %&gt;&lt;/p&gt;

```
  &amp;lt;h3&amp;gt;Small Appliances&amp;lt;/h3&amp;gt;
  &amp;lt;% form.fields_for :small_appliances do |sm_appl_form| 

```

%&gt;  
&lt;%= render :partial =&gt; ‘rooms/small\_appliance’,  
:locals =&gt; { :form =&gt; sm\_appl\_form } %&gt;  
&lt;% end %&gt;  
&lt;p class=“addLink”&gt;&lt;%= add\_child\_link “[+]  
Add new small appliance”, form, :small\_appliances  
%&gt;&lt;/p&gt;

```
  &amp;lt;p&amp;gt;&amp;lt;%= form.submit "Submit"

```

%&gt;&lt;/p&gt;  
&lt;% end %&gt;

_application\_helper.rb_

```
module ApplicationHelper
  def remove_child_link(name, form)
    form.hidden_field(:_delete) + link_to_function(name,

```

“remove\_fields(this)”)  
end

```
  def add_child_link(name, form, method)
    fields = new_child_fields(form, method)
    link_to_function(name, h("insert_fields(this, \"#{method}\",

```

"#{escape\_javascript(fields)}")"))  
end

```
  def new_child_fields(form_builder, method, options = {})
    options[:object] ||=

```

form\_builder.object.class.reflect\_on\_association(method).klass.new  
options[:partial] ||= method.to\_s.singularize  
options[:form\_builder\_local] ||= :form  
form\_builder.fields\_for(method, options[:object], :child\_index  
=\> “new\_#{method}”) do |form|  
render(:partial =\> options[:partial], :locals =\> {  
options[:form\_builder\_local] =\> form })  
end  
end  
end

_public/javascripts/application.js_

```
function insert_fields(link, method, content) {
  var new_id = new Date().getTime();
  var regexp = new RegExp("new_" + method, "g")
  $(link).up().insert({
    before: content.replace(regexp, new_id)
  });
}

function remove_fields(link) {
  var hidden_field = $(link).previous("input[type=hidden]");
  if (hidden_field) {
    hidden_field.value = '1';
  }
  $(link).up(".fields").hide();
}

```

Thanks,  
Ryan
