同一对象上有多个多态关联

时间:2018-11-16 10:07:48

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

我有一个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

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

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

谢谢

2 个答案:

答案 0 :(得分:2)

需要更改的应通报协会。在这种情况下,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关联无法自行提取密钥。

答案 1 :(得分:1)

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

第三行覆盖第一行:

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