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.
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.