Collection_select and has_many :through

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.

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

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