【发布时间】:2012-07-21 00:05:41
【问题描述】:
我试图了解has_many :through 是什么以及何时使用它(以及如何使用它)。但是,我不明白。我正在阅读Beginning Rails 3 并尝试使用谷歌搜索,但我无法理解。
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-3 activerecord
我试图了解has_many :through 是什么以及何时使用它(以及如何使用它)。但是,我不明白。我正在阅读Beginning Rails 3 并尝试使用谷歌搜索,但我无法理解。
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-3 activerecord
假设你有这些模型:
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
【讨论】:
current_user.patient.appointment.last.conversation.messages 检索约会对话。是否有 nested has_many through 之类的东西?
假设您有两个模型: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吗?还是一切都由这个协会处理?
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。
【讨论】: