← Back to Upcase

has_many :through association


(Jameson Trinker) #1

I was hoping some body could walk me through the has_many :through association in Rails. I feel like these and polymorphic associations are the last thing holding me back from ‘getting it’.

How can I be certain when to use them? Anyone know some questions I can ask myself when considering it? Also, how do I know which models the has_many :through goes on and which model needs the belongs_to?

If you could walk me through this like I’m a 5th grader that would be great.


(Geoff Harcourt) #2

has_many :through can be a useful way to reduce the amount of code you need to write, but I have found that it is best to use it sparingly. It’s easy to allow one “god” class in your application like “User” to “own” too many models through overuse of this association.

has_many :through is used when you have a model that needs to access the associated models of a model for which there’s already a has_many association. Since that sounds messy, let’s look at it in a sample business domain.

A Company has many Departments. Each department has several Employees.

class Company < ActiveRecord::Base
  has_many :departments
end

class Department < ActiveRecord::Base
  belongs_to :company
  has_many :employees
end

class Employee < ActiveRecord::Base
   belongs_to :department
end 

There might be scenarios where you want to access all the employees of a given company, but you don’t want to have to collect the departments and then use the departments’ IDs to query the employees table. A quick way to get at the employees who work for a given company would be to use a has_many :through relationship. I’ll alter the Company class now to add that relationship.

class Company < ActiveRecord::Base
   has_many :departments
   has_many :employees, through: :departments
end

This relationship allows you to directly access any employees of a company through an #employees method added to the model.

my_company = Company.find(1)
my_company.employees         #AR:Relation of all employees at company

Employee doesn’t get a “belongs_to” relation to link back to Company, but you could do this with a delegation.

class Employee < ActiveRecord::Base
   belongs_to :department

   delegate :company, to: :department
end 

Be careful not to overdo it with delegators. If you have a long chain of delegation going on, you’re probably trying to do too much with your model, and it’s suffering from feature envy.

Hope this helps.


(Jameson Trinker) #3

Thanks very much. This is absolutely the best explanation I’ve heard. I appreciate the long response!