Соединение двух моделей в Ruby on Rails - PullRequest
2 голосов
/ 01 апреля 2009

Я застрял на этом весь день. У меня есть настройки, подобные приведенной ниже. Я пытаюсь определить друзей, используя ассоциацию group_memberships.

class User < ActiveRecord::Base
  has_many :group_memberships
  has_many :groups, :through => :group_memberships
  has_many :friends # what goes here? <<
end

class GroupMembership < ActiveRecord::Base
  belongs_to :user
  belongs_to :role
  belongs_to :group
end

class Role < ActiveRecord::Base
  has_many :group_memberships
end

class Group < ActiveRecord::Base
  has_many :group_memberships
  has_many :users, :through > :group_memberships
end

Я бы хотел сделать это без создания объединяющего стола для друзей, если только это не безумие.

Таблица group_membership содержит user_id и group_id, связывающие одного пользователя с одной группой.

Я бы пытался получить

@user.friends

чтобы вернуть пользователей с общими group_memberships, используя group_id.

has_many :friends, :through => :group_memberships, :source => :group

Ничто из того, что я пробовал, не работает, но я объясню это до моего полного недопонимания приведенного выше кода.

Ответы [ 3 ]

4 голосов
/ 01 апреля 2009

К сожалению, Rails не позволяет вам вкладывать в has_many более 2 глубины. Забудем на мгновение назвать его friends (назовем его users), теоретически это будет то, что вам нужно:

has_many :group_memberships
has_many :groups, :through => :group_memberships
has_many :users, :through => groups

За исключением того, что это не работает. Если вы попробуете это, вы увидите это не очень полезное сообщение об ошибке, которое приходит из этого бита кода, в частности source_reflection.options[:through].nil?. То есть through не может иметь самого through.

Вместо этого вы можете захотеть сделать что-то вроде этого:

Решение 1

class User < ActiveRecord::Base
  has_many :group_memberships
  has_many :groups, :through => :group_memberships

  def friends
    groups.with_users.map(&:users).flatten.uniq.reject{|u| u == self}
  end
end

class Group < ActiveRecord::Base
  has_many :group_memberships
  has_many :users, :through => :group_memberships

  named_scope :with_users, :include => :users
end

Решение 2

Используйте плагин nested_has_many_through, который упоминал Радар. Похоже, что по крайней мере одна вилка этого на github была обновлена ​​для работы на последних Rails.

Решение 3 (только для пинка)

или, просто ради удовольствия, вы можете сделать это одним большим запросом SQL:

class User < ActiveRecord::Base
  has_many :group_memberships
  has_many :groups, :through => :group_memberships

  def friends
    sql = <<-SQL
      SELECT users.* FROM users, (
        SELECT DISTINCT gm2.user_id AS user_id
        FROM group_memberships gm, groups g, group_memberships gm2
        WHERE gm.user_id = ? AND g.id = gm.group_id AND gm2.group_id = g.id AND gm2.user_id != ?
      ) AS user_ids
      WHERE users.id = user_ids.user_id
    SQL
    User.find_by_sql([sql, id, id])
  end
end
1 голос
/ 01 апреля 2009

Используйте плагин nested_has_many_through .

0 голосов
/ 02 апреля 2009

делегат: пользователи,: to => 'группа'

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