I got an IM this afternoon from a friend, pointing to part of the Active Record Query Interface guide:

Then you could call Client.males.all to get all the clients who are male. Please note that if you do not specify the all on the end you will get a Scope object back, not a set of records which you do get back if you put the all on the end.


Setting up a simple named scope and testing it in irb certainly seems to indicate that this passage is wrong:

[sourcecode language='ruby']
Client.males.is_a?(Array) => true
Client.males.is_a?(ActiveRecord::NamedScope::Scope)
=> false
[/sourcecode]

And yet, a moment's reflection says that named scopes can't simply be returning arrays of ActiveRecord objects: if they were, there would be no way to compose them.

As with other Rails questions, the easiest way to answer this is to fire up a text editor and dig into the Rails source - in this case, activerecord/lib/active_record/named_scope.rb, which contains the definition of the Scope object and the other named scope apparatus. There you'll find this chunk of code:

[sourcecode language='ruby']
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
[/sourcecode]

So: except for a small set of explicitly-listed methods, the Scope object delegates everything to :proxy_found. And what is that? Read a bit further in the source and you'll find out:

[sourcecode language='ruby']
def proxy_found
@found || load_found
end

def load_found
@found = find(:all)
end
[/sourcecode]

So: for any method not in its small list - say, the inspect that IRB uses to display the value of an expression - the Scope looks at its internal results array, running the find to do so if necessary. Thus we have an object that at first glance appears to be something other than what it really is. Problem solved.