2

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?

berkes
  • 26,996
  • 27
  • 115
  • 206
  • 2
    Hm, doesn't plain aliasing do the job? – Sergio Tulentsev Sep 26 '15 at 11:18
  • @SergioTulentsev, yes it does. It's just slightly more complicated then defining an alias on an instance-method, because of the class-eval thing. Maybe you can put this in an answer with some code so we can close this question? – berkes Sep 26 '15 at 15:07

1 Answers1

1

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.

dimakura
  • 7,575
  • 17
  • 36
  • Won't `old_in_sale = self.in_sale` trigger the actual proc, and instead have `old_in_sale` contain the list of Prodcucts, instead of a pointer to the scope? – berkes Sep 26 '15 at 15:08
  • @berkes you are right. I've updated my answer. Btw, old code still performs well in simple cases. `old_in_sale` contains `ActveRecord::Relation` which is reused on each query. It will be broken though, if what old `in_sale` returns will be different from what we get on first execution. – dimakura Sep 26 '15 at 15:27