2010-03-09 7 views
4

У меня есть несколько проектов. Эти проекты имеют пользователей через членство.Глубокие отношения в Rails

Однако эти пользователи принадлежат к компаниям. Вопрос в том, как узнать, какие компании могут получить доступ к проекту?

В идеале я смогу сделать project.users.companies, но это не сработает.

Есть ли приятный, приятный способ сделать это?

+0

Я нашел этот вопрос интересным - с has_many вы можете использовать has_many: через, но с has_and_belongs_to_many вы должны быть немного более креативными. – kikito

+0

http://en.wikipedia.org/wiki/Law_of_Demeter –

+0

@Arnis: Закон Деметры уважается здесь. Используются только прямые компоненты объекта O. См. Мой ответ ниже. – kikito

ответ

0

Другие ответы, как представляется, пренебрегают членами, которые вы упомянули. Если это фактические объекты, которые у вас есть, то то, что вы решите сделать, зависит от размера ваших таблиц. Если они не очень огромные, то решение «более ОО» вероятно, будет выглядеть примерно так:

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 

Это немного меньше чистой, но поставит большую часть обработки ближайшего данные и только при соединении из трех таблиц не должны заканчиваться тем, что генерируют такое огромное количество кортежей, что ваша СУБД разваливается на что-то похожее.

0

У вас должна быть возможность установить отношения до: project.users.companies.

Ассоциации являются:

Project has_one User belongs_to Company 
+0

Я не знаю, работает ли этот синтаксис. –

+0

Ах, это значит, что это код psuedo, чтобы продемонстрировать ассоциации. Не фактический код как таковой. –

+0

Это не сработает для меня, так как проекты и пользователи - многие-ко-многим. –

0

Я думаю, что вы можете сделать что-то вроде этого.

class Project < ActiveRecord::Base 
    def self.companies 
    Company.all(:conditions => { :users => { :project_id => @project.id } }, :include => :users) 
    end 
end 

Но прошло какое-то время, так как я использовал эти функции, поэтому я могу быть ржавым.

Редактировать: это может не сработать. Не уверен, что я получил :include или :join справа. Но, как я уже сказал, я ржавый.

1

Я предполагаю, что у вас есть это:

class Project < ActiveRecord::Base 
    has_and_belongs_to_many :users 
end 

class User < ActiveRecord::Base 
    has_and_belongs_to_many :projects 
    belongs_to :company 
end 

class Company < ActiveRecord::Base 
    has_many :users 
end 

И вы хотите, чтобы получить project.companies. Менее болезненным я могу представить:

class Project < ActiveRecord::Base 
    has_and_belongs_to_many :users 
    def companies 
    Company.all(
     :joins => {:users => :projects}, 
     :conditions => {'projects_users.project_id' => self.id} 
    ).uniq 
    end 
end 

Обратите внимание на uniq в конце. Он удалит дублированные компании.

Смежные вопросы