示例:
假设我们有一个具有多态关联的模型提醒。
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的关系代理的可链接性,我更愿意将其编写为类方法(而不是显式范围(。