Ruby-on-rails 何时在 Rails 中使用“has_many :through”关系?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11600928/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When to use a "has_many :through" relation in Rails?
提问by LuckyLuke
I am trying to understand what has_many :throughis and when to use it (and how). However, I am not getting it. I am reading Beginning Rails 3 and I tried Googling, but I am not able to understand.
我试图了解什么has_many :through是以及何时使用它(以及如何使用)。但是,我不明白。我正在阅读 Beginning Rails 3 并尝试使用谷歌搜索,但我无法理解。
回答by cpuguy83
Say you have these models:
假设你有这些模型:
Car
Engine
Piston
A car has_one :engine
An engine belongs_to :car
An engine has_many :pistons
Piston belongs_to :engine
汽车has_one :engine
发动机belongs_to :car
发动机has_many :pistons
活塞belongs_to :engine
A car has_many :pistons, through: :engine
Piston has_one :car, through: :engine
汽车has_many :pistons, through: :engine
活塞has_one :car, through: :engine
Essentially you are delegating a model relationship to another model, so instead of having to call car.engine.pistons, you can just do car.pistons
本质上,您将模型关系委托给另一个模型,因此不必调用car.engine.pistons,您只需执行car.pistons
回答by Ben Scheirman
Say you have two models: Userand Group.
假设您有两个模型: User和Group。
If you wanted to have users belong to groups, then you could do something like this:
如果您想让用户属于组,那么您可以执行以下操作:
class Group < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
belongs_to :group
end
What if you wanted to track additional metadata around the association? For example, when the user joined the group, or perhaps what the user's role is in the group?
如果您想跟踪关联的其他元数据怎么办?例如,用户何时加入群组,或者用户在群组中的角色是什么?
This is where you make the association a first class object:
这是您使关联成为第一类对象的地方:
class GroupMembership < ActiveRecord::Base
belongs_to :user
belongs_to :group
# has attributes for date_joined and role
end
This introduces a new table, and eliminates the group_idcolumn from the user's table.
这会引入一个新表,并group_id从用户表中删除该列。
The problem with this code is that you'd have to update every where else you use the user class and change it:
这段代码的问题是你必须更新你使用用户类的所有其他地方并更改它:
user.groups.first.name
# becomes
user.group_memberships.first.group.name
This type of code sucks, and it makes introducing changes like this painful.
这种类型的代码很糟糕,它使得引入这样的更改很痛苦。
has_many :throughgives you the best of both worlds:
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
Now you can treat it like a normal has_many, but get the benefit of the association model when you need it.
现在你可以把它当作一个普通的has_many,但是在你需要的时候获得关联模型的好处。
Note that you can also do this with has_one.
请注意,您也可以使用has_one.
Edit: Making it easy to add a user to a group
编辑:轻松将用户添加到组
def add_group(group, role = "member")
self.group_associations.build(:group => group, :role => role)
end
回答by Todd A. Jacobs
ActiveRecord Join Tables
ActiveRecord 连接表
has_many :throughand has_and_belongs_to_manyrelationships 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.
has_many :through和has_and_belongs_to_many关系通过连接表发挥作用,连接表是一个中间表,表示其他表之间的关系。与 JOIN 查询不同,数据实际上存储在表中。
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.
使用has_and_belongs_to_many,您不需要主键,您可以通过 ActiveRecord 关系而不是通过 ActiveRecord 模型访问记录。当您希望以多对多关系链接两个模型时,通常会使用 HABTM。
You use a has_many :throughrelationship 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.
has_many :through当您希望与作为 Rails 模型的连接表进行交互时,您可以使用关系,完成主键和将自定义列添加到连接数据的能力。后者对于与连接行相关但并不真正属于相关模型的数据尤其重要——例如,存储从连接行中的字段派生的计算值。
See Also
也可以看看
In A Guide to Active Record Associations, the recommendation reads:
在A Guide to Active Record Associations 中,建议如下:
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.
最简单的经验法则是,如果您需要将关系模型作为独立实体使用,您应该设置一个 has_many :through 关系。如果您不需要对关系模型做任何事情,设置 has_and_belongs_to_many 关系可能更简单(尽管您需要记住在数据库中创建连接表)。
如果您需要验证、回调或连接模型上的额外属性,您应该使用 has_many :through。

