Другие ответы, кажется, пренебрегают членством, которое вы упомянули. Если это реальные объекты, записи о которых у вас есть, то, что вы решите сделать, зависит от размера ваших таблиц. Если они не очень большие, то решение "more OO", вероятно, будет выглядеть примерно так:
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
Это может не очень хорошо работать, так как он извлекает много данных из базы данных, а затем выполняет всю фильтрацию в памяти, но его довольно интуитивно понятно. Если вы хотите перенести все вычисления в базу данных, я думаю, что хорошее решение, скорее всего, будет выглядеть примерно так в классе Project:
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
Это немного менее чисто, но большая часть обработки будет располагаться ближе к данным, и при объединении только в три таблицы не должно получиться такое огромное количество кортежей, что ваша СУБД развалится на первый взгляд.