Claw
Claw

Reputation: 767

Why doesn't #is_a? work with an instance of ActiveRecord::NamedScope::Scope

I'm using Rails 2.3.9. To illustrate the issue, suppose we have a named scope on a model:

class Book < ActiveRecord::Base
  named_scope :has_isbn, :conditions => 'isbn IS NOT NULL'
end

If you get the class of the named scope, ActiveRecord::NamedScope::Scope is returned:

Book.has_isbn.class
# => ActiveRecord::NamedScope::Scope

However, if you use #is_a? or === to figure out whether it is a scope, it returns false:

Book.has_isbn.is_a?(ActiveRecord::NamedScope::Scope)
# => false
ActiveRecord::NamedScope::Scope === Book.has_isbn
# => false

Does anyone know why this is happening? Calling a named scope returns an instance of ActiveRecord::NamedScope::Scope (if you look at lib/active_record/named_scope.rb in the Rails code, you can see it calls Scope.new and returns it), so why doesn't #is_a? and === return true?

Upvotes: 2

Views: 1740

Answers (1)

Michelle Tilley
Michelle Tilley

Reputation: 159115

Check out this code from the Scope class:

NON_DELEGATE_METHODS = %w(nil? send object_id class extend find size count sum average maximum minimum paginate first last empty? any? respond_to?).to_set
[].methods.each do |m|
  unless m =~ /^__/ || NON_DELEGATE_METHODS.include?(m.to_s)
    delegate m, :to => :proxy_found
  end
end

Every method in [].methods--that is, every method an array responds to--is defined on the Scope instance to pass through to the proxy object, except for the methods defined in the NON_DELEGATE_METHODS array. These are untouched, and notice that class is listed in there.

So, when you call scope.class, you get Scope as the response. But when you call scope.is_a?, you're actually calling scope.proxy_found.is_a?, and the proxy object in this case is an Array.

>> scope.is_a?(Array)
=> true

Upvotes: 3

Related Questions