I just found this out myself; I have no idea why this was kept secret from me for so long. If you need an interface for linking multiple pre-existing model_ones to each of your model_twos, your first thought might be accepts_nested_attributes_for. While that is a great and versatile tool, it is definitely not easy for every situation, of which I think this is one. You would probably get stuck trying to figure out the best way to remove old links, recognize existing ones, and add new ones, all in as simple an interface as possible for the user. For instance, wouldn’t this multi-select box be nice?
That was what I wanted. What I found out (again?) was that you could do exactly that by writing simply:
<%= f.select :platform_ids, Platform.all.map{|p| [p.name, p.id]}, {}, :multiple => true %>
(Assuming that Game has_many :platforms, :through => :platform_relationships. Remember to put :platform_ids in your attr_accessible!)
So there you are. Rails really is magic. It seems that any has_many association recognizes an array of ids as a valid way to list and alter its child relationships in bulk, though the benefit for :through associations is much more meaningful. The syntax is the collection’s name in singular + “_ids”, and the documentation claims the following:
collection_singular_ids=ids
Replace the collection with the objects identified by the primary keys in ids. This method loads the models and calls collection=.
A few notes:
- Any children orphaned by this operation which are defined as :dependent => :destroy will be destroyed! This is probably helpful clean-up, but definitely be aware of it.
- For a :through association, the join model will be deleted, not destroyed (no destroy callbacks), and this appears to be independent of :dependent => :destroy. This may not have adverse effects in most situations, and in fact is probably a good thing as the relationship model is automatically groomed for you.
- If any of the child assignments doesn’t pass validation, the whole operation will fail.
- The assignment operation cannot go through multiple join models, though you can get the current array of ids. This makes sense in the end, because the second or third join models are probably not simple join models for which we have all the information necessary to create from scratch.
Enjoy!
-Comatose