Ruby on rails 如何别名或重写作用域并调用原始作用域?

Ruby on rails 如何别名或重写作用域并调用原始作用域?,ruby-on-rails,scopes,Ruby On Rails,Scopes,Spree插件添加了一个作用域。比如说: class Product scope :in_sale, -> { where(in_sale: true) } end 请注意,这个过程稍微复杂一些 现在,我想在我的装饰器中覆盖它: Spree::Product.class_eval do scope :in_sale, -> { on_hand.where(in_sale: true) } end 我宁愿调用原始的。where(in_sale:true),而不是复制的原始实

Spree插件添加了一个作用域。比如说:

class Product
  scope :in_sale, -> { where(in_sale: true) }
end
请注意,这个过程稍微复杂一些

现在,我想在我的装饰器中覆盖它:

Spree::Product.class_eval do
  scope :in_sale, -> { on_hand.where(in_sale: true) }
end
我宁愿调用原始的
。where(in_sale:true)
,而不是复制的原始实现


您如何重新使用原始范围,这与您通常调用
别名\u方法\u chain:foo,:feature
作为实例方法的方式类似?

在不知道问题背后的原因的情况下,我建议使用:

product.in_sale.on_hand
而不是修补
Spree::Product
class

如果在一次方法调用中仍需要此功能,可以这样做:

Spree::Product.class_eval do
  # alias an old method
  class <<self
    alias_method :old_in_sale, :in_sale
  end

  # reusing old method in a new one
  scope :in_sale, -> { old_in_sale.on_hand }
end

正如@berkes在下面的评论中所指出的,它只对
old_in_sale
计算一次,并且这个值将在将来重新使用。它仍然可能产生正确的结果,但不能保证。

Hm,普通别名不起作用吗?@SergioTulentsev,是的。由于类eval的原因,这比在实例方法上定义别名稍微复杂一些。也许你可以用一些代码来回答这个问题,这样我们就可以结束这个问题了。
old_in_sale=self.in_sale
不会触发实际的进程,而是让
old_in_sale
包含产品列表,而不是指向范围的指针吗?@berkes你是对的。我已经更新了我的答案。顺便说一句,旧代码在简单的情况下仍然表现良好
old_in_sale
包含在每个查询中重复使用的
ActveRecord::Relation
。但是,如果旧的销售中的
返回的内容与我们第一次执行时得到的内容不同,它将被打破。
Spree::Product.class_eval do
  old_in_sale = in_sale

  # reusing old method in a new one
  scope :in_sale, -> { old_in_sale.on_hand }
end