有没有办法将多态组合的解包重构到其模型中



示例:

假设我们有一个具有多态关联的模型提醒。

class Reminder < ActiveRecord::Base
  belongs_to :rememberable, polymorphic: true
  scope :events, -> { where(rememberable_type: 'Event') }
end

然后,我可以通过以下方式获得所有记住的事件的列表

events = Reminder.events.map(&:rememberable)

问题:

有没有办法将其放入多态关联的扩展或提醒范围内?这样我们就可以这样称呼它:

events = Reminder.events.unpack

我尝试过:

我试过了

class Reminder < ActiveRecord::Base
  belongs_to :rememberable, polymorphic: true do
    def unpack
      map(&:rememberable)
    end
  end
  scope :events, -> { where(rememberable_type: 'Event') }
end

class Reminder < ActiveRecord::Base
  belongs_to :rememberable, polymorphic: true
  scope :events, -> { where(rememberable_type: 'Event') }
  scope :unpack, -> { to_a.map(&:rememberable) }
end

没有成功。

旁注:

我知道,有一个范围结束ActiveRecord的关系代理的可链性是普遍的不良做法。

除了破坏ActiveRecord关系链之外,通过使用map和/或to_a,您将遇到性能问题,这些强制获取所有现有记录并在Rails进程中循环访问它们。

因此,与其">查找现有提醒事项并给我关联的事件",不如">查找至少有一个关联提醒的事件"。事实上,在设计关联范围时,应始终从期望结果中的模型开始。不要尝试在 Reminder 中实现将返回 Event 集合的作用域。

1-让我们创建一个关注点:

module Rememberable
  extend ActiveSupport::Concern
  included do |base|
    base.scope :with_reminders, -> { joins :reminders }
  end  
end

2-将该问题包含在您的模型中

class Event < ActiveRecord::Base
  include Rememberable
  ...

3-使用它

events = Event.with_reminders

这其实很简单。您可以在 Rails 中使用类方法作为作用域。因此,让我们编写类方法(在Reminder(:

def self.unpack
  @relation.map(&rememberable)
end

或者,如果您更喜欢作用域语法:

scope :unpack, -> { @relation.map(&rememberable) }

但是,由于它结束了ActiveRecord的关系代理的可链接性,我更愿意将其编写为类方法(而不是显式范围(。