可能具有“多态 has_one” Rails 中的关系?
我想做这样的事情:
Category
--------
- id
- name
Tag
--------
- id
- tag
Campaign
--------
- id
- name
- target (either a tag *or* a category)
多态关联是这里的答案吗?我似乎不知道如何将它与 has_one :target, :as => 一起使用:可瞄准。
基本上,我希望将 Campaign.target 设置为标签或类别(或将来可能的另一个模型)。
I'd like to do something like this:
Category
--------
- id
- name
Tag
--------
- id
- tag
Campaign
--------
- id
- name
- target (either a tag *or* a category)
Is a polymorphic association the answer here? I can't seem to figure out how to use it with has_one :target, :as => :targetable.
Basically, I want Campaign.target to be set to a Tag or a Category (or potentially another model in the future).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不认为您在这里需要
has_one
关联,belongs_to
应该是您正在寻找的。在这种情况下,您需要在 Campaign 表中添加
target_id
和target_type
列,您可以使用t.references :target< 在 rake 中创建这些列/code> 调用(其中
t
是table
变量)。现在,营销活动可以与
Tag
或Category
关联,并且@campaign.target
将返回相应的标签。如果目标表上有一个指向您的
Campaign
的外键,则将使用has_one
关联。例如,您的表格将包含
Tag:id、tag、campaign_id
Category:id、category、campaign_id
并且两者都会有一个
belongs_to :campaign
关联。在这种情况下,您必须使用has_one :tag
和has_one :category
,但此时您无法使用通用target
观点。这更有意义吗?
编辑
由于
target_id
和target_type
实际上是另一个表的外键,因此您的Campaign
属于其中一个。我可以看到您对措辞的困惑,因为从逻辑上讲,Campaign
是容器。我想您可以将其视为Campaign
有一个目标,即Tag
或Container
,因此它属于>标签
或容器
。has_one
表示关系是在目标类上定义的。例如,Tag
将通过has_one
关系与营销活动关联,因为标签类上没有任何内容可以标识该关联。在这种情况下,您将拥有一个
Category
。在这里,:as
关键字告诉 Rails 哪个关联与此Tag
相关。 Rails 不知道如何预先解决这个问题,因为与Campaign
上的名称tag
没有关联。另外两个可能会造成进一步混淆的选项是
source
和source_type
选项。这些仅用于:through
关系,在这种关系中,您实际上是通过
另一个表加入关联。文档可能描述得更好,但是source
定义了关联名称,而source_type
用于该关联是多态的。仅当目标关联(在:through
类上)具有不明显的名称时才需要使用它们 - 就像上面使用target 和
Tag 的情况 - - 我们需要告诉 Rails 使用哪一个。I don't believe you're in need of a
has_one
association here, thebelongs_to
should be what you're looking for.In this case, you'd want a
target_id
andtarget_type
column on your Campaign table, you can create these in a rake with at.references :target
call (wheret
is thetable
variable).Now campaign can be associated to either a
Tag
orCategory
and@campaign.target
would return the appropriate one.The
has_one
association would be used if you have a foreign key on the target table pointing back to yourCampaign
.For example, your tables would have
Tag: id, tag, campaign_id
Category: id, category, campaign_id
and would have a
belongs_to :campaign
association on both of them. In this case, you'd have to usehas_one :tag
andhas_one :category
, but you couldn't use a generictarget
at this point.Does that make more sense?
EDIT
Since
target_id
andtarget_type
are effectively foreign keys to another table, yourCampaign
belongs to one of them. I can see your confusion with the wording because logically theCampaign
is the container. I guess you can think of it asCampaign
has a single target, and that's aTag
or aContainer
, therefore it belongs in aTag
orContainer
.The
has_one
is the way of saying the relationship is defined on the target class. For example, aTag
would have be associated to the campaign through ahas_one
relationship since there's nothing on the tag class that identifies the association. In this case, you'd haveand likewise for a
Category
. Here, the:as
keyword is telling rails which association relates back to thisTag
. Rails doesn't know how to figure this out upfront because there's no association with the nametag
on theCampaign
.The other two options that may provide further confusion are the
source
andsource_type
options. These are only used in:through
relationships, where you're actually joining the associationthrough
another table. The docs probably describe it better, but thesource
defines the association name, andsource_type
is used where that association is polymorphic. They only need to be used when the target association (on the:through
class) has a name that isn't obvious -- like the case above withtarget and
Tag -- and we need to tell rails which one to use.这个问题的答案很好,但我只是想提一下另一种方法来完成同样的任务。您可以做的是创建两个关系,例如:
验证确保您不会意外地设置两个字段,并且
target
帮助程序允许对标签/类别进行多态访问。这样做的好处是您可以获得更正确的数据库模式,您可以在 id 列上定义适当的外键约束。这也将导致数据库级别上更好、更高效的 SQL 查询。
The answers to this questions are great, but I just wanted to mention another way to accomplish the same. What you could do instead is create two relationships, eg.:
The validation ensures that you don't accidentally end up with both fields set, and the
target
helpers allows polymorphic access to the tag/category.The benefit of doing it like this is that you get a somewhat more correct database schema, where you can define proper foreign key constraints on the id columns. This will also lead to nicer and more efficient sql queries on the database level.
轻微附录:在创建
Campaign
表的迁移中,t.references :target
调用应具有:polymorphic => true
(至少在 Rails 4.2 中)Slight addendum: In the migration where you created the
Campaign
table, thet.references :target
call should have:polymorphic => true
(at least with rails 4.2)