Scoped query in Ruby model with with same name as `Enumerator#chain`

Viewed 69

A lot of models in our application have a chain query. Something like this:

scope :chain, ->(c) { where(chain: c) }

This works fine in Ruby 2.5, the current version we are using. But in Ruby 2.6, an Enumerator#chain method was added. So now, an expression like this:

criteria = Model.other_query.chain(@chain)

will call the Enumerator method (which returns an Enumerator::Chain object) instead of the model query.

It works fine if I use the chain method first:

criteria = Model.chain(@chain).other_query

Is there a way to get the expression to call the model query instead that does not involve renaming all the instances of our chain method, or rearranging all the calls?

Cheers!

1 Answers

The problem is that ActiveRecord::Relation include Enumerable that is included in Enumerator so when you call Model.other_query.chain(@chain) chain will be Enumerator#chain.

What you could do is something like reopening ActiveRecord::Relation (or prepend a Module), define a new chain method that check self. I guess that if Model is in ancestors you should call Model.chain otherwise super. Something like this. I did not check it you may give it a try.

module ChainPrepend
  def chain
    if self.ancestors.inlcude? Model
      Model.chain # how make Model in scope here ?
    else
      super
    end
  end
end

class ActiveRecord::Relation
  prepend ChainPrepend
end
Related