什么时候应该在Rails中使用"has_many:through"关系?

Luc*_*uke 116 activerecord ruby-on-rails ruby-on-rails-3

我试图了解什么has_many :through是什么以及何时使用它(以及如何使用).但是,我没有得到它.我正在阅读Beginning Rails 3,我尝试使用谷歌搜索,但我无法理解.

cpu*_*y83 193

假设你有这些模型:

Car
Engine
Piston
Run Code Online (Sandbox Code Playgroud)

汽车has_one :engine
发动机belongs_to :car
发动机has_many :pistons
活塞belongs_to :engine

一辆汽车has_many :pistons, through: :engine
活塞has_one :car, through: :engine

基本上你是将模型关系委托给另一个模型,所以car.engine.pistons你可以这样做而不必打电话car.pistons

  • 我称之为SACA - ShortAndClearAnswer. (23认同)
  • 这很有意义! (7认同)
  • 答案非常清楚,可以理解. (5认同)

Ben*_*man 171

假设你有两个型号: UserGroup.

如果您想让用户属于组,那么您可以执行以下操作:

class Group < ActiveRecord::Base
  has_many :users
end

class User < ActiveRecord::Base
  belongs_to :group
end
Run Code Online (Sandbox Code Playgroud)

如果您想跟踪关联周围的其他元数据,该怎么办?例如,当用户加入群组时,或者用户角色在群组中的位置?

这是您将关联作为第一类对象的地方:

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

  # has attributes for date_joined and role
end
Run Code Online (Sandbox Code Playgroud)

这引入了一个新表,并group_id从用户表中删除了该列.

此代码的问题在于您必须更新使用用户类的其他位置并更改它:

user.groups.first.name

# becomes

user.group_memberships.first.group.name
Run Code Online (Sandbox Code Playgroud)

这种类型的代码很糟糕,它使得引入这样的变化变得很痛苦.

has_many :through 为您提供两全其美:

class User < ActiveRecord::Base
  has_many :groups, :through => :group_memberships  # Edit :needs to be plural same as the has_many relationship   
  has_many :group_memberships
end
Run Code Online (Sandbox Code Playgroud)

现在,您可以像平常一样对待它has_many,但在需要时可以获得关联模型的好处.

请注意,您也可以这样做has_one.

编辑:轻松将用户添加到组中

def add_group(group, role = "member")
  self.group_associations.build(:group => group, :role => role)
end
Run Code Online (Sandbox Code Playgroud)

  • 这是我在“用户”模型上添加方法以添加组的地方。就像我刚才所做的编辑一样。希望这可以帮助。 (2认同)

Tod*_*obs 17

ActiveRecord加入表

has_many :throughhas_and_belongs_to_manyrelationship通过连接表来起作用,连接表是一个表示其他表之间关系的中间表.与JOIN查询不同,数据实际存储在表中.

实际差异

使用时has_and_belongs_to_many,您不需要主键,而是通过ActiveRecord关系而不是通过ActiveRecord模型访问记录.当您想要链接具有多对多关系的两个模型时,通常使用HABTM.

has_many :through当您想要作为Rails模型与连接表进行交互时,可以使用关系,包括主键以及向已连接数据添加自定义列的功能.后者对于与连接行相关的数据尤为重要,但并不真正属于相关模型 - 例如,存储从连接行中的字段派生的计算值.

也可以看看

"活跃记录协会指南"中,建议如下:

最简单的经验法则是,如果需要将关系模型作为独立实体使用,则应设置has_many:through关系.如果您不需要对关系模型执行任何操作,则设置has_and_belongs_to_many关系可能更简单(尽管您需要记住在数据库中创建连接表).

如果需要在连接模型上进行验证,回调或额外属性,则应使用has_many:through.