可能具有“多态 has_one” Rails 中的关系?

发布于 2024-12-03 06:07:08 字数 294 浏览 0 评论 0原文

我想做这样的事情:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

世界和平 2024-12-10 06:07:08

我不认为您在这里需要 has_one 关联,belongs_to 应该是您正在寻找的。

在这种情况下,您需要在 Campaign 表中添加 target_idtarget_type 列,您可以使用 t.references :target< 在 rake 中创建这些列/code> 调用(其中 ttable 变量)。

class Campaign < ActiveRecord::Base
  belongs_to :target, :polymorphic => true
end

现在,营销活动可以与 TagCategory 关联,并且 @campaign.target 将返回相应的标签。

如果目标表上有一个指向您的 Campaign 的外键,则将使用 has_one 关联。

例如,您的表格将包含

Tag:id、tag、campaign_id
Category:id、category、campaign_id

并且两者都会有一个 belongs_to :campaign 关联。在这种情况下,您必须使用 has_one :taghas_one :category,但此时您无法使用通用 target观点。

这更有意义吗?

编辑

由于target_idtarget_type实际上是另一个表的外键,因此您的Campaign属于其中一个。我可以看到您对措辞的困惑,因为从逻辑上讲,Campaign 是容器。我想您可以将其视为 Campaign 有一个目标,即 TagContainer,因此它属于 >标签容器

has_one 表示关系是在目标类上定义的。例如,Tag 将通过 has_one 关系与营销活动关联,因为标签类上没有任何内容可以标识该关联。在这种情况下,您将拥有

class Tag < ActiveRecord::Base
  has_one :campaign, :as => :target
end

一个 Category。在这里,:as 关键字告诉 Rails 哪个关联与此 Tag 相关。 Rails 不知道如何预先解决这个问题,因为与 Campaign 上的名称 tag 没有关联。

另外两个可能会造成进一步混淆的选项是 sourcesource_type 选项。这些仅用于 :through 关系,在这种关系中,您实际上是通过另一个表加入关联。文档可能描述得更好,但是 source 定义了关联名称,而 source_type 用于该关联是多态的。仅当目标关联(在 :through 类上)具有不明显的名称时才需要使用它们 - 就像上面使用 target 和Tag 的情况 - - 我们需要告诉 Rails 使用哪一个。

I don't believe you're in need of a has_one association here, the belongs_to should be what you're looking for.

In this case, you'd want a target_id and target_type column on your Campaign table, you can create these in a rake with a t.references :target call (where t is the table variable).

class Campaign < ActiveRecord::Base
  belongs_to :target, :polymorphic => true
end

Now campaign can be associated to either a Tag or Category 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 your Campaign.

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 use has_one :tag and has_one :category, but you couldn't use a generic target at this point.

Does that make more sense?

EDIT

Since target_id and target_type are effectively foreign keys to another table, your Campaign belongs to one of them. I can see your confusion with the wording because logically the Campaign is the container. I guess you can think of it as Campaign has a single target, and that's a Tag or a Container, therefore it belongs in a Tag or Container.

The has_one is the way of saying the relationship is defined on the target class. For example, a Tag would have be associated to the campaign through a has_one relationship since there's nothing on the tag class that identifies the association. In this case, you'd have

class Tag < ActiveRecord::Base
  has_one :campaign, :as => :target
end

and likewise for a Category. Here, the :as keyword is telling rails which association relates back to this Tag. Rails doesn't know how to figure this out upfront because there's no association with the name tag on the Campaign.

The other two options that may provide further confusion are the source and source_type options. These are only used in :through relationships, where you're actually joining the association through another table. The docs probably describe it better, but the source defines the association name, and source_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 with target andTag -- and we need to tell rails which one to use.

太阳公公是暖光 2024-12-10 06:07:08

这个问题的答案很好,但我只是想提一下另一种方法来完成同样的任务。您可以做的是创建两个关系,例如:

class Campaign < ActiveRecord::Base
  belongs_to :tag
  belongs_to :category
  validate :tag_and_category_mutually_exclusive

  def target=(tag_or_category)
    case
    when tag_or_category.kind_of?(Tag)
      self.tag = tag_or_category
      self.category = nil
    when tag_or_category.kind_of?(Category)
      self.category = tag_or_category
      self.tag = nil
    else
      raise ArgumentError, "Expected Tag or Category"
    end
  end

  def target(tag_or_category)
    tag || category
  end

  private 
  def tag_and_category_mutually_exclusive
    if tag && category
      errors.add "Can't have both a tag and a category"
    end
  end
end

验证确保您不会意外地设置两个字段,并且 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.:

class Campaign < ActiveRecord::Base
  belongs_to :tag
  belongs_to :category
  validate :tag_and_category_mutually_exclusive

  def target=(tag_or_category)
    case
    when tag_or_category.kind_of?(Tag)
      self.tag = tag_or_category
      self.category = nil
    when tag_or_category.kind_of?(Category)
      self.category = tag_or_category
      self.tag = nil
    else
      raise ArgumentError, "Expected Tag or Category"
    end
  end

  def target(tag_or_category)
    tag || category
  end

  private 
  def tag_and_category_mutually_exclusive
    if tag && category
      errors.add "Can't have both a tag and a category"
    end
  end
end

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.

浪漫人生路 2024-12-10 06:07:08

轻微附录:在创建 Campaign 表的迁移中,t.references :target 调用应具有 :polymorphic => true (至少在 Rails 4.2 中)

Slight addendum: In the migration where you created the Campaign table, the t.references :target call should have :polymorphic => true (at least with rails 4.2)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文