Jeremy Kemper has just checked in a change to Edge Rails that fixes my biggest frustration with has_many :through. Since it’s appearance a couple of versions back, has_many :through has been a great addition to the rails associations toolkit, making the use of join models infinitely cleaner. But until recently it was rather cumbersome to create those relationships.

For example, if I wanted to add an author to a book where the relationship is defined as:

has_many :authors, :through => :involvements,
  :class_name => 'Contributor'

The simplest it could be to find and create an author and set up a link was:

book.involvements.create!(
  :author => Contributor.find_or_create_by_name(name))
book.authors(true)

Now it’s as simple as:

book.authors < < Contributor.find_or_create_by_name(name)

The one gotcha comes if your book object is a new record, and so doesn’t yet have an ID. Trying the above in that case will raise ActiveRecord::HasManyThroughCantAssociateNewRecords.

Since in my particular case I’m masking the association behind a proxy attribute, I considered getting around the problem by dynamically creating (and subsequently removing) after_save callbacks, but for now I’ve simply changed my controller to create the associations after the record is saved. Maybe Edge Rails will have some more options to offer us before long.

Thanks to Josh Susser for the original report. Check out his post for more detail and examples.