【问题标题】:Has_many, through associationHas_many,通过关联
【发布时间】:2011-03-28 20:10:22
【问题描述】:

警告:Total Rails Newb (TRN)。这应该是一个非常基本的问题,所以我希望有人能抽出几分钟的时间来帮助阐明一下。

假设我有以下模型:用户、组和成员 一个用户可以有很多组(比如朋友、家人等) 一个组可以有许多成员,即其他用户。

我将如何构建它?

最初我尝试过这个:

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

class Groups < ActiveRecord::Base
  has_many :users, :through => :members
  belongs_to :user
end

class Member < ActiveRecord::Base
  belongs_to :group
  belongs_to :user
end

但是这给了我一个用户错误,所以我改变了

has_many :groups, :through => :members

has_many :memberships, :through => :members, :source => :groups

当我尝试做时仍然收到关于缺少关联的错误

group = Group.new
group.user.new

【问题讨论】:

    标签: ruby-on-rails-3


    【解决方案1】:

    会有用的:http://railscasts.com/episodes/47-two-many-to-many

    class User < ActiveRecord::Base
      has_many :members
      has_many :groups, :through => :members
      has_many :groups_as_owner, :class_name => "Group"
    end
    
    class Groups < ActiveRecord::Base
      has_many :members
      has_many :users, :through => :members
      belongs_to :owner, :class_name => "User", :foreign_key => :user_id
    end
    
    class Member < ActiveRecord::Base
      belongs_to :group
      belongs_to :user
    end
    

    【讨论】:

    • 为什么当您调用user.groups 时会在返回的数组中多次显示该组?例如,如果您在一个组中有 2 个成员并调用 user.groups,那么该组将在数组中出现两次,因为它与 2 个成员相关联
    • 因为这是自然行为。它不会返回 uniq 组,而是返回所有关联的组,就像成员拥有的一样多。您可以随时调用user.groups.uniqDISTINCT sql 来为用户返回uniq 组。但实际上您所说的问题实际上与验证有关。您应该验证您创建的数据的唯一性。
    • 嗯,它不会在数据库中创建多个“组 #2”,因此所有组 ID 在数据库中都是唯一的,它不应该是验证的东西。它只是多次返回唯一组,因为它与成员连接。所以你可能只是使用user.groups.uniq 来返回一个唯一的集合是正确的。谢谢解释
    • 它正在创建多个具有相同引用的members,因此它是关于验证member
    • 很好的答案!这就是问题所在。仍然缺少 1 个链接,即用户是组的一部分,但用户也是组的所有者。所以每个组都需要有一个 user_id 字段来指示哪个用户拥有它。虽然 has_many_through 关系的指南很清楚,但它们并没有告诉您如何处理两个模型之间的多个关系。
    【解决方案2】:

    基本上 has_many-through 关联是 n:m 关联(连接表),它(应该)具有更多属性,而不仅仅是连接记录 id 的 id...

    所以你有一个表 Groups(有一个 id),一个表 Users(有一个 id)和一个表 Members(没有 id,但是 user_id 和 group_id)

    基本上,您所做的几乎是正确的,只需考虑您如何从用户访问组,反之亦然....

    用户将首先查找其成员信息,并通过该成员信息访问组信息......反之亦然

    所以你先设置

    has_many :members
    

    然后调用

    has_many :groups, :through => :members
    

    你只需要

    class User < ActiveRecord::Base
      has_many :members
      has_many :groups, :through => :members
    end
    
    class Groups < ActiveRecord::Base
      has_many :members
      has_many :users, :through => :members
    end
    
    class Member < ActiveRecord::Base
      belongs_to :group
      belongs_to :user
    end
    

    而您的上述代码中还有另一个错误

    你可能想使用

    user = group.users.new
    

    而不是

    user = group.user.new
    

    【讨论】:

    • 我又慢了几秒钟 :-)
    【解决方案3】:

    试试这个结构:

    class User < ActiveRecord::Base
      has_many :members
      has_many :groups, :through => :members
    end
    
    class Groups < ActiveRecord::Base
      has_many :members
      has_many :users, :through => :members
    end
    
    class Member < ActiveRecord::Base
      belongs_to :group
      belongs_to :user
    end
    

    另外看看has_and_belongs_to_many,如果你不需要与类成员做,那么你应该使用has_and_belongs_to_many。在这种情况下不要忘记在数据库中创建连接表

    【讨论】:

    • has_and_belongs_to_many 现在经常被替换为 has_many :through 因为人们发现(正如我从实际经验中知道的那样)通常开始时带有两个 ID 的简单链接表,很快就会更改为反映需要的其他属性,即使只是日期字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多