简体   繁体   中英

Multiple polymorphic associations on the same object

I have a Flag model which is joined to multiple other objects with FlagInstance and a polymorphic flaggable on that table:

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

With has many_through I'm able to fetch any flaggable object like user.flags which is great.

However I'm trying to flag objects with errors and the notify other objects so I've added

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

The problem is, a User can have a flag and can be notified of a flag. So user.flags isn't specific enough to show me which is a flag and which is a notification of a flag .

I think I need to change the relationships:

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

But I'm not sure what to change them to. Can someone please suggest a solution?

Note: both flags and notifications of flags can belong to multiple objects, so they both need to remain polymorphic.

Thanks

Association for notifiable needs to be changed. In this case 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'

Note: You might also need to provide foreign_key in case Rails association is not able to pick up the key itself.

Each association must have a unique name - otherwise the later definition will just overwrite the former.

Here the third line overwrites the first line:

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

To reference the correct associations we would need to setup the user model as so:

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

In your case you might want to use concerns to keep it dry:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM