views:

356

answers:

3

I have 3 classes related by habtm associations...Users, Locations, Employees.

Users is related to Locations via a habtm relationship, and Locations is related to Employees via a habtm relationship.

What I would like to be able to do is say:

current_user.locations.employees

Does anyone know the "Rails Way" to do this? I can do it in SQL, but I am wondering if there is a cleaner way.

A: 

I assume that the following is true and that your ActiveRecords will reflect this.

user belongs_to location
location has_many users
location has_many employees
employee belongs_to location

then you can say in your User ActiveRecord

has_many :employees :through => :locations

I think that should work.

UPDATE:

Just realized that your user has many locations as well. Not quite sure if the above will work or not. Worth a try though.

thomas
+1  A: 

Hi Lee,

You can extend associations in ActiveRecord:

class User

  has_many :locations do

    def employees
      # Use whatever logic you'd like here.
      locations.find(:all, :include => [:employees]).collect {|l| l.employees }
    end

  end

end

u = User.find 1
u.locations.employees #=> calls our method defined above

And see this:

http://ryandaigle.com/articles/2006/12/3/extend-your-activerecord-association-methods

You may also try has_many :through:

class User

  has_many :user_locations
  has_many :locations, :through => :user_locations


  # Not sure if you can nest this far, this guy has problems with it:
  # http://tim.theenchanter.com/2008/10/how-to-hasmany-through-hasmany-through.html
  #
  # Maybe if locations was a habtm instead of :through? experiment with it!
  #
  has_many :employees, :through => :locations

end

u = User.find 1
u.employees #=> Uses associations to figure out the SQL

In general, Lee, I'm concerned about your data model. HABTM relationships are not really recommended now. Using has_many :through allows you to name the join table, and then you can store attributes on a relationship with better business meaning. I would say the "Railsy" thing is to add some through relationships to expose more domain modelling.

Also, some example models would be helpful to really understand your question.

Good luck!

mixonic
A: 

You could define method in User sort of like the following

def get_all_related_employees
    employees = []
    self.locations.each do |location|
       employees << location.employees
    end
    employees
end

or you could do it right inline

current_user.locations.map {|location| location.employees }.each do |employee|
  puts employee.name
end
ErsatzRyan