OK, super-lame for answering my own question, but based on comment from @m_x and Railscast 239 http://railscasts.com/episodes/239-activerecord-relation-walkthrough I deeper into the Rails source code... I can see that Relation respond_to
honors, and method_missing
prefers an Array method to any other method not explicitly defined for Relation.
# from rails/active_record/relation/delegation.rb
def respond_to?(method, include_private = false)
super || Array.method_defined?(method) ||
@klass.respond_to?(method, include_private) ||
arel.respond_to?(method, include_private)
end
protected
def method_missing(method, *args, &block)
if Array.method_defined?(method)
::ActiveRecord::Delegation.delegate method, :to => :to_a
to_a.send(method, *args, &block)
elsif @klass.respond_to?(method)
::ActiveRecord::Delegation.delegate_to_scoped_klass(method)
scoping { @klass.send(method, *args, &block) }
elsif arel.respond_to?(method)
::ActiveRecord::Delegation.delegate method, :to => :arel
arel.send(method, *args, &block)
else
super
end
end
So, if you name an ActiveRecord "scoping" class method the same as an Array instance method, the Relation will be converted to an Array and the Array method will be called instead of your class method.
Easy solution: just pick another method name.