Being still relatively new to Rails, I continue to stumble across corners that I haven’t encountered before, and this is one of those times. I’ve got two models that are connected with a join table — not an unusual thing. The join table also has an attribute that needs to be set, which is in turn connected with another table. This all works fine with has_many :through, but then it came time for me to instantiate a relationship in code, and it took me some time to find information on how exactly to create the join table instance with the attribute. Now that I figured it out, I want to share.
I have changed the names of the models to anonymize my work here, but the idea remains the same. It may seem weird, though, that an address can have many users. Just live with it for my sake, okay? Thanks.
class User < ActiveRecord::Base has_many :address_users has_many :addresses, :through => :address_users end class Address < ActiveRecord::Base has_many :address_users has_many :users, :through => :address_users end class UserAddress < ActiveRecord::Base belongs_to :user belongs_to :address belongs_to :address_type end class AddressType < ActiveRecord::Base end
Nothing too unusual there. However, the address_users table has both a user_id and address_id, as well as an address_type_id. So that needs to be set when an address is added to a user. The address types, for the sake of argument, are “home” (id=1) and “work” (id=2).
So, I was working away on some code to import records, and I have a User, and a set of Addresses. Now I want to add those addresses, and associate them with the appropriate users — and set the address_type. That was a problem. I first simply had:
user_list = (code to fill array of users) address.users = user_list
Well, that was easy. Except that address_type was NULL for every entry, of course. So, after searching around, I finally discovered something that works — I don’t know yet if it’s the best way, so anyone reading this with something better, please comment! But this is what I have now:
home_address = AddressType.find_by_name("Home") user_list.each do |u| address.address_user.build(:user => u, :address_type => home_address) end
And that creates each user-address relationship and sets the type appropriately. (BTW, I know that hard-coding “Home” is BAD and that’s just to make things simple here)