何时在 Rails 中使用“has_many :through”关系?
Posted
技术标签:
【中文标题】何时在 Rails 中使用“has_many :through”关系?【英文标题】:When to use a "has_many :through" relation in Rails? 【发布时间】:2012-07-21 00:05:41 【问题描述】:我试图了解has_many :through
是什么以及何时使用它(以及如何使用它)。但是,我不明白。我正在阅读Beginning Rails 3 并尝试使用谷歌搜索,但我无法理解。
【问题讨论】:
【参考方案1】:假设你有这些模型:
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
【讨论】:
我称之为 SACA - ShortAndClearAnswer。 在这个例子中,我们有 3 个模型。如果我们想要超过 3 个模型怎么办?例如一个医生/患者应用程序,他们可以在其中发送消息。然后用户 has_one Patient has_many Appointments has_one Conversation has_many Messages。然后可以使用current_user.patient.appointment.last.conversation.messages
检索约会对话。是否有 nested has_many through 之类的东西?
我们在这里真正谈论的是活动记录关系。它是关于 SQL 查询以及如何获取相关数据的。【参考方案2】:
假设您有两个模型:User
和 Group
。
如果您想让用户属于组,那么您可以执行以下操作:
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 :group_memberships
has_many :groups, :through => :group_memberships # Edit :needs to be plural same as the has_many relationship
end
现在您可以像对待普通的has_many
一样对待它,但在需要时可以利用关联模型。
请注意,您也可以使用 has_one
执行此操作。
编辑:轻松将用户添加到组
def add_group(group, role = "member")
self.group_associations.build(:group => group, :role => role)
end
【讨论】:
这是我在user
模型上添加方法以添加组的地方。类似于我刚刚进行的编辑。希望这会有所帮助。
我明白了,我也必须写user.groups << group
吗?还是一切都由这个协会处理?
我有一个与 group_membership 相同的课程,但我在使用 factory girl 时遇到问题,您能帮帮我吗?
我会使用“has_many :group_memberships”。使用单数会起作用,但 user.group_membership 会是一个集合,而 user.group_memberships 不会起作用。
那是一个错字。固定。【参考方案3】:
ActiveRecord 连接表
has_many :through
和has_and_belongs_to_many
关系通过一个连接表 起作用,它是一个中间表,表示其他表之间的关系。与 JOIN 查询不同,数据实际上存储在表中。
实际差异
使用has_and_belongs_to_many
,您不需要主键,您可以通过 ActiveRecord 关系而不是通过 ActiveRecord 模型访问记录。当您想以多对多关系链接两个模型时,通常会使用 HABTM。
当您希望作为 Rails 模型与连接表进行交互时,您可以使用has_many :through
关系,并使用主键和向连接数据添加自定义列的能力。后者对于与连接行相关但并不真正属于相关模型的数据尤其重要——例如,存储从连接行中的字段派生的计算值。
另见
在A Guide to Active Record Associations 中,建议内容如下:
最简单的经验法则是,如果您需要将关系模型作为独立实体使用,您应该设置一个 has_many :through 关系。如果您不需要对关系模型做任何事情,那么设置 has_and_belongs_to_many 关系可能会更简单(尽管您需要记住在数据库中创建连接表)。
如果您需要验证、回调或连接模型上的额外属性,您应该使用 has_many :through。
【讨论】:
以上是关于何时在 Rails 中使用“has_many :through”关系?的主要内容,如果未能解决你的问题,请参考以下文章
何时在 Ruby on Rails 中使用 memoization
何时在 Rails 中使用“has_many :through”关系?
何时在 Elastic Beanstalk 中使用多容器 docker 来运行 Rails 应用程序?