has_many , :through

Posted by Jake Good
on Aug 13, 06

I have been working on wheresmycomedian.com quite a bit today and I’m so incredibly excited (possibly too excited) about through associations in Ruby on Rails. It’s sad that I’m regurgitating an example from a really good article explaining the differences between the two many-to-many association models… but I’m going to put it into my own context for wheresmycomedian.com.



So here’s a simple scenario: I have a list of comedians that do shows at venues… how can I get meaningful associations between the objects?



Traditionally you would create a many-to-many relationship using habtm, which in turn makes a calling JOIN statement to find the relevant association.



You could do something like this:






1
2
3
4
5
6
7
8
9
10
11
12
13
14

class Comedian < ActiveRecord::Base
acts_as_taggable
validates_presence_of :name, :description
has_and_belongs_to_many :shows
end

class Show < ActiveRecord::Base
validates_presence_of :date
validates_presence_of :name
validates_presence_of :venue
belongs_to :venue
has_and_belongs_to_many :comedians
end


The schema is simple, code is simple… but what about this… Sometimes you might have a show that has multiple comedians. Each comedian appears at specific times… and you want to be able to model that within the show. Maybe your users only want to see a particular comedian and only wants to know about the times they are appearing.



This causes a problem, as the join association is purely a SQL statement, not a meaningful association.



Enter in has_many, :through. The concept is simple, create an association model that holds the meaningful data (ex. time of appearance). Using some ruby syntax, we can still have our clean model code and associations…






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

class Comedian < ActiveRecord::Base
acts_as_taggable
validates_presence_of :name, :description
has_many :appearances, :dependent => true
has_many :shows, :through => :appearances
end

class Show < ActiveRecord::Base
validates_presence_of :date
validates_presence_of :name
validates_presence_of :venue
belongs_to :venue
has_many :appearances, :dependent => true
has_many :comedians, :through => :appearances
end

class Appearance < ActiveRecord::Base
validate_presence_of :date
belongs_to :comedian
belongs_to :show
end


Excellent! Now we can have meaningful data… with the Appearance holding the date of the comedians appearance…



Once we get the :uniq patch, we’ll be able to specify more distinct associations… without specifying an ugly select statement in our :through clause. Another really sweet thing about has_many is that we can have polymorphic (heterogenous) associations… nice.

Comments

Leave a response

Comment