К сожалению, 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