The other answers seem to neglect the members you mentioned. If these are the actual objects that you have, then what you decide to do depends on the size of your tables. If they are not terribly huge, then the βmore OOβ solution would probably look something like this:
class Project < ActiveRecord::Base has_many :memberships has_many :users, :through => :memberships def user_companies self.users.map {|user| user.companies}.flatten.uniq end end class Membership < ActiveRecord::Base belongs_to :user belongs_to :project end class User < ActiveRecord::Base has_many :memberships has_many :projects, :through => :memberships belongs_to :company end class Company < ActiveRecord::Base has_many :users end
This may not work fine, as it extracts a lot of data from the database and then performs all the filtering in memory, but it is pretty intuitive to read. If you want to transfer all calculations to the database, I think that a good solution will most likely look something like this in the Project class:
def user_companies Company.find_by_sql("SELECT company.* FROM companies, users, memberships WHERE companies.id = users.company_id AND users.id = memberships.user_id AND memberships.project_id = #{self.id}") end
This is a little less clean, but will put most of the processing closer to the data, and only in three table joins should the creation of such a huge number of tuples fail that your DBMS is falling apart. It seems that
source share