Глубокие отношения в Rails - PullRequest
4 голосов
/ 09 марта 2010

У меня есть несколько проектов. У этих проектов есть пользователи через членство.

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

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

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

Ответы [ 4 ]

1 голос
/ 09 марта 2010

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

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

Обратите внимание на уникальность в конце. Это удалит дублирующиеся компании.

0 голосов
/ 09 марта 2010

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

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

0 голосов
/ 09 марта 2010

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

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

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

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

0 голосов
/ 09 марта 2010

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

Ассоциации:

Project has_one User belongs_to Company
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...