berkes
berkes

Reputation: 27573

How can you alias, or otherwise override, a scope and call the original?

A Spree addon adds a scope. Let's say:

class Product
  scope :in_sale, -> { where(in_sale: true) }
end

Note that the actual scope is slightly more complex.

Now, I want to override that in my decorator:

Spree::Product.class_eval do
  scope :in_sale, -> { on_hand.where(in_sale: true) }
end

Instead of the copied over original implementation of .where(in_sale: true), I would prefer to call the original.

How can you re-use an original scope, somewhat similar to how you would normally call alias_method_chain :foo, :feature for instance-methods?

Upvotes: 2

Views: 703

Answers (1)

dimakura
dimakura

Reputation: 7655

Without actually knowing what's behind the problem, I would suggest to use:

product.in_sale.on_hand

instead of patching Spree::Product class.

If you still require this in one method call, you can do it like this:

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

Broken

This code seemingly works:

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

As @berkes notes in his comment below, it evaluates only once for old_in_sale and this value is being reused in the future. It still might produce correct results, but it's not guarantied.

Upvotes: 1

Related Questions