# Collection\_select and has\_many :through

**URL:** <https://www.ruby-forum.com/t/collection-select-and-has-many-through/177731>\
**Category:** Rails\
**Created:** [October 22, 2009, 6:12pm UTC](https://www.ruby-forum.com/t/collection-select-and-has-many-through/177731 "2009-10-22T18:12:55Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 22, 2009, 6:12pm UTC](https://www.ruby-forum.com/t/collection-select-and-has-many-through/177731/1 "2009-10-22T18:12:55Z")

</div>

I am having a bit of an issue with updating multiple models from one  
form - and in particular the collection\_select related to a has\_many  
through relationship.  
I have the following models:  
(Location is a pseudo-class which really acts as the join model for  
the others.)

class Location \< ActiveRecord::Base  
belongs\_to :address  
belongs\_to :organisation  
belongs\_to :address\_type

Then the other models are as follows:

class Address \< ActiveRecord::Base  
has\_many :locations  
has\_many :address\_types, :through =\> :locations  
has\_many :organisations, :through =\> :locations

class Organisation \< ActiveRecord::Base  
has\_many :locations  
has\_many :addresses, :through  
=\> :locations, :include=\>:address\_types

class AddressType \< ActiveRecord::Base  
has\_many :locations  
has\_many :addresses, :through =\> :location

An organisation can have a number of different addresses (main,  
dispatch, invoice etc). And one address can belong to more than one  
organisation (to allow for different companies operating out of the  
same address), and an address can be more than one type of address (ie  
the invoice address could be the same as the dispatch address, but  
different to the main office address).

I have a form that allows a user to add a new address (uses Ryan  
Bates’ “Handle Multiple Models in One Form” technique from the  
Advanced Rails Recipes book and it has a pulldown to allow the user to  
say what this address is.

Here is the relevant part of the Organisations model:  
after\_update :save\_addresses

def new\_address\_attributes=(address\_attributes)  
#handles the address edit form in the edit view  
address\_attributes.each do |attributes|  
addresses.build(attributes)  
end  
end

def existing\_address\_attributes=(address\_attributes)  
addresses.reject(&:new\_record?).each do |address|  
attributes = address\_attributes[address.id.to\_s]  
if attributes  
address.attributes = attributes  
else  
addresses.delete(address)  
end  
end  
end

def save\_addresses  
addresses.each do |address|  
address.save(false)  
end  
end

And here is the addresses controller  
class AddressesController \< ApplicationController  
def new  
@address = Address.new  
@organisation = Organisation.find(params[:organisation\_id])  
@locations = Location.find\_all\_by\_organisation\_id(params  
[:organisation\_id])  
@address.locations.build  
respond\_to do |format|  
format.html # new.html.erb  
format.js {render :partial =\> ‘form’, :locals =\> { :address =\>  
@address, :organisation =\> @organisation, :location=\>@locations }}

The problem I am having is that the save doesn’t update the  
address\_type\_id in the locations table. Everything else is updated  
correctly, just not that one field.  
Being an old-fashioned PHP programmer, I am slightly struggling to  
find out how to make it update that field as well.  
It seems the problem lies in the collection\_select in the form. And I  
am not sure how to construct this collection\_select to get round this.  
The docs say:  
collection\_select(object, method, collection, value\_method,  
text\_method, options = {}, html\_options = {})

which is not exactly clear … however I have, through trial-and-error  
found that “method” appears to relate to the field or column of the  
table from which the data is drawn. So if I want the address\_type\_id  
to be passed, this means that the object must surely be built using  
the location object - except that doesn’t work. I constantly get  
“NoMethodError” for anything in that field except “:id” - which is not  
what I want included in the parameters hash at all - I want the  
address\_type\_id in there. (I have tried debug location - and it is the  
correct object)

This is in the address/\_form.erb.html which gets called by the AJAX  
call:  
\<% fields\_for “organisation[new\_address\_attributes][]”, location  
do |location\_form| %\>  
Address type \<%= location\_form.collection\_select  
(:address\_type\_id, get\_address\_types(organisation.id), :id, :name,  
{}) %\>

(the get\_address\_types thing is a function that only allows the values  
that haven’t already been used - can’t have an organisation with two  
invoice addresses for example).

I love it when Rails works - but it is an absolute bugger and a half  
when it doesn’t as you can’t get at anything. You can’t see what is  
going on - so you can’t see where to jump in to insert the data in the  
appropriate place - or how to pass it correctly in the first place.  
Days like this make me wish I had stuck with PHP …

PS this is a re-post of an earlier post when I had thought the problem  
related to HABTM - but it doesn’t appear to be.

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 22, 2009, 6:38pm UTC](https://www.ruby-forum.com/t/collection-select-and-has-many-through/177731/2 "2009-10-22T18:38:40Z")

</div>

Arrrrggghhh…  
Why is it - that 20 seconds after posting a problem - you find at  
least a partial solution?  
My problem was passing the wrong information in the locations local  
variable -  
@locations = Location.find\_all\_by\_organisation\_id(params  
[:organisation\_id])  
Since I was creating a new entry I needed a new one to work on in  
memory  
I think … think it should be  
@locations = @address.locations.build

That seems to be passing the correct information over - it is just  
turning up in the wrong place now - it is coming into the  
new\_address\_attributes, but of course that is not an attribute of an  
address - it is an attribute of a location - so I think I need a  
function to handle that in the same way.  
This sort of thing makes PHP feel like a pair of old slippers - not  
very trendy, but secretly you love them

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [October 22, 2009, 7:44pm UTC](https://www.ruby-forum.com/t/collection-select-and-has-many-through/177731/3 "2009-10-22T19:44:16Z")

</div>

Arrrrggghhh…  
Why is it - that 20 seconds after posting a problem - you find at  
least a partial solution?  
My problem was passing the wrong information in the locations local  
variable -  
@locations = Location.find\_all\_by\_organisation\_id(params  
[:organisation\_id])  
Since I was creating a new entry I needed a new one to work on in  
memory  
I think … think it should be  
@locations = @address.locations.build

That seems to be passing the correct information over - it is just  
turning up in the wrong place now - it is coming into the  
new\_address\_attributes, but of course that is not an attribute of an  
address - it is an attribute of a location - so I think I need a  
function to handle that in the same way.  
This sort of thing makes PHP feel like a pair of old slippers - not  
very trendy, but secretly you love them
