在Ruby on Rails中将两个模型链接在一起

时间:2009-04-01 02:49:48

标签: ruby-on-rails ruby

我整天都被困在这一天。我有一个类似下面的设置。我正在尝试使用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_id返回具有公共group_membership的用户。

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

我没有尝试过任何工作,但我会说明我完全误解了上述代码。

3 个答案:

答案 0 :(得分:4)

不幸的是,Rails不允许你将has_many的嵌套深度超过2个..忘记将它命名为friends一会儿(让我们称之为users),理论上这就是你的想法想:

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

除非这不起作用。如果你尝试它,你会看到this不那么有用的错误消息来自this位代码,特别是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

使用Radar提到的nested_has_many_through插件。看起来github上的至少one fork已更新为最新的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 :(得分:1)

使用nested_has_many_through插件。

答案 2 :(得分:0)

委托:users,:to =&gt; '基团'