【问题标题】:Multiple polymorphic associations on the same object同一对象上的多个多态关联
【发布时间】:2018-11-16 10:07:48
【问题描述】:

我有一个Flag 模型,该模型通过FlagInstance 和该表上的多态flaggable 连接到多个其他对象:

table 'flag_instances'
flag_id
flaggable_id
flaggable_type
.....

有了 many_through,我可以获取任何可标记的对象,例如 user.flags,这很棒。

但是我试图标记有错误的对象并通知其他对象,所以我添加了

table 'flag_instances'
flag_id
flaggable_id
flaggable_type
notifiable_id
notifiable_type
.....

问题是,User 可以有一个标志,并且可以通知一个标志。所以user.flags 不够具体,无法告诉我哪个是flag,哪个是flag 的通知。

我想我需要改变关系:

user.rb
has_many :flag_instances, as: :flaggable, dependent: :destroy
has_many :flags, through: :flag_instances
has_many :flag_instances, as: :notifiable, dependent: :destroy
has_many :flags, through: :flag_instances

但我不确定将它们更改为什么。有人可以提出解决方案吗?

注意:标志和标志通知都可以属于多个对象,所以它们都需要保持多态性。

谢谢

【问题讨论】:

  • 标志和通知必须在同一个条目中吗?我的意思是当一个 flag_instances 条目是一个标志时,它也可以同时是通知吗?即单个条目在所有 4 个中都有值:flaggable_id, flaggable_type, notifiable_id, and notifiable_type 列?
  • 是的,每个条目都将始终填充所有 4 个条目。有时它们会包含相同的对象,但通常是不同的对象(例如,将 AccessToken 标记为过期并通知用户)

标签: ruby-on-rails ruby ruby-on-rails-5 polymorphic-associations


【解决方案1】:

需要更改通知的关联。在这种情况下 user.rb:

has_many :flag_instances, as: :flaggable, dependent: :destroy
has_many :flags, through: :flag_instances

has_many :notifiables, as: :notifiable, dependent: :destroy, class_name: 'FlagInstance'
has_many :notifications, through: :notifiables, class_name: 'Flag'

注意:您可能还需要提供foreign_key,以防 Rails 关联无法自行获取密钥。

【讨论】:

    【解决方案2】:

    每个关联必须有一个唯一的名称 - 否则后面的定义只会覆盖前者。

    这里第三行覆盖了第一行:

    has_many :flag_instances, as: :flaggable, dependent: :destroy
    has_many :flags, through: :flag_instances
    has_many :flag_instances, as: :notifiable, dependent: :destroy
    

    要引用正确的关联,我们需要这样设置用户模型:

    class User < ApplicationRecord
      has_many :flag_instances_as_flaggable, 
         as: :flaggable
         class_name: 'FlagInstance'
      has_many :flags_as_flaggable, 
         through: :flag_instances_as_flaggable, 
         source: :flag
      has_many :flag_instances_as_notifiable, 
         as: :notifiable
         class_name: 'FlagInstance'
      has_many :flags_as_notifiable,
         through: :flag_instances_as_notifiable,
         source: :flag
    end
    

    在您的情况下,您可能希望使用关注点来保持干燥:

    module Flaggable
      extend ActiveSupport::Concern
      included do
        has_many :flag_instances_as_flaggable, 
          as: :flaggable,
          class_name: 'FlagInstance'
        has_many :flags_as_flaggable,
          through: :flag_instances_as_flaggable, 
          source: :flag
      end
    end
    
    module Notifiable
      extend ActiveSupport::Concern
      included do
        has_many :flag_instances_as_notifiable, 
          as: :notifiable,
          class_name: 'FlagInstance'
        has_many :flags_as_notifiable,
          through: :flag_instances_as_notifiable,
          source: :flag
      end
    end
    
    class User < ApplicationRecord
      include Flaggable
      include Notifiable
    end
    

    【讨论】:

    • 我相信 Suryas 的回答是正确的。但只是想知道,在您的解决方案中,活动记录如何知道在名为 flag_instances 的表中查找?
    • 我实际上忘了添加class_name: 'FlagInstance',这是因为类的名称不能从关联的名称中被嘲笑。
    • 是这样想的。谢谢!
    • 当您指定 source: 时,在 though: 关联中不需要它,因为 AR 从它所经过的关联(标志)中获取类名。
    • 我可能会使用单独的 Notification 模型来执行此操作,而不是将所有内容都硬塞到一个类中。这使您可以创建 m-2-m 关联,以便您可以跟踪应用内通知,例如电子邮件通知。
    猜你喜欢
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多