什么时候在Rails中使用“ has_many:through”关系?


123

我试图了解什么has_many :through是什么以及何时使用(以及如何使用)。但是,我不明白。我正在阅读Beginning Rails 3,并尝试了Googling,但我听不懂。

Answers:


177

假设您有两个模型: UserGroup

如果您希望用户属于组,则可以执行以下操作:

class Group < ActiveRecord::Base
  has_many :users
end

class User < ActiveRecord::Base
  belongs_to :group
end

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

这是使关联成为一流对象的地方:

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

  # has attributes for date_joined and role
end

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

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

user.groups.first.name

# becomes

user.group_memberships.first.group.name

这种类型的代码很烂,并且使引入这样的更改变得很痛苦。

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

现在,您可以像对待普通对象一样对待它has_many,但是在需要时可以从关联模型中受益。

请注意,您也可以使用has_one

编辑:轻松添加用户到组

def add_group(group, role = "member")
  self.group_associations.build(:group => group, :role => role)
end

2
这是我在user模型上添加方法以添加组的地方。就像我刚才所做的编辑一样。希望这可以帮助。
Ben Scheirman

我知道,我也必须写user.groups << group吗?还是一切都由该协会处理?
LuckyLuke 2012年

我有一个与group_membership相同的类,使用工厂女孩时遇到了问题,您能帮我吗?
艾曼·萨拉

我将使用“ has_many:group_memberships”。使用单数将有效,但user.group_membership将适用于集合,而user.group_memberships将无效。
calasyr 2015年

那是一个错字。固定。
Ben Scheirman

212

假设您有以下模型:

Car
Engine
Piston

汽车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


9
这很有意义!
RajG 2014年

24
我称之为SACA-ShortAndClearAnswer。
Asme,2014年

18

ActiveRecord联接表

has_many :throughhas_and_belongs_to_many关系通过函数连接表,这是一个表示其它表之间的关系的中间表。与JOIN查询不同,数据实际上存储在表中。

实际差异

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

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

也可以看看

“活动记录关联指南”中,建议如下:

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.