我试图了解has_many :through
它是什么以及何时使用它(以及如何使用它)。但是,我不明白。我正在阅读Beginning Rails 3 并尝试使用谷歌搜索,但我无法理解。
3 回答
假设你有这些模型:
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
假设您有两个模型: 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
ActiveRecord Join Tables
has_many :through
and has_and_belongs_to_many
relationships function through a join table, which is an intermediate table that represents the relationship between other tables. Unlike a JOIN query, data is actually stored in a table.
Practical Differences
With has_and_belongs_to_many
, you don't need a primary key, and you access the records through ActiveRecord relations rather than through an ActiveRecord model. You usually use HABTM when you want to link two models with a many-to-many relationship.
You use a has_many :through
relationship when you want to interact with the join table as a Rails model, complete with primary keys and the ability to add custom columns to the joined data. The latter is particularly important for data that is relevant to the joined rows, but doesn't really belong to the related models--for example, storing a calculated value derived from the fields in the joined row.
See Also
In A Guide to Active Record Associations, the recommendation reads:
The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don’t need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship (though you’ll need to remember to create the joining table in the database).
You should use has_many :through if you need validations, callbacks, or extra attributes on the join model.