Другие ответы, как представляется, пренебрегают членами, которые вы упомянули. Если это фактические объекты, которые у вас есть, то то, что вы решите сделать, зависит от размера ваших таблиц. Если они не очень огромные, то решение «более ОО» вероятно, будет выглядеть примерно так:
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
Это немного меньше чистой, но поставит большую часть обработки ближайшего данные и только при соединении из трех таблиц не должны заканчиваться тем, что генерируют такое огромное количество кортежей, что ваша СУБД разваливается на что-то похожее.
Я нашел этот вопрос интересным - с has_many вы можете использовать has_many: через, но с has_and_belongs_to_many вы должны быть немного более креативными. – kikito
http://en.wikipedia.org/wiki/Law_of_Demeter –
@Arnis: Закон Деметры уважается здесь. Используются только прямые компоненты объекта O. См. Мой ответ ниже. – kikito