---
title: "Under the hood  how named_scope works"
description:
  "named_scope is awesome. But how does it work. How does it pull off all those
  tricks which seem magical. This blog takes a deep dive and looks into code to
  see how named_scope really works."
canonical_url: "https://www.bigbinary.com/blog/under-the-hood-how-named-scope-works"
markdown_url: "https://www.bigbinary.com/blog/under-the-hood-how-named-scope-works.md"
---

# Under the hood how named_scope works

named_scope is awesome. But how does it work. How does it pull off all those
tricks which seem magical. This blog takes a deep dive and looks into code to
see how named_scope really works.

- Author: Neeraj Singh
- Published: October 17, 2008
- Categories: Rails

_Following code was tested with ruby 1.8.7 and Rails 2.x_ .

Rails recently added named_scope feature and it is a wonderful thing. If you
don't know what `named_scope` is then you can find out more about it
[here](http://railscasts.com/episodes/108) .

This article is not about how to use `named_scope`. This article is about how
`named_scope` does what it does so well.

## Understanding with_scope

ActiveRecord has something called `with_scope` which is not associated with
`named_scope`. The two are entirely separate thing. However `named_scope` relies
on the workings on `with_scope` to do its magic. So in order to understand how
`named_scope` works first let's try to understand what `with_scope` is.

`with_scope` let's you add scope to a model in a very extensible manner.

```ruby
def self.all_male
  with_scope(:find => {:conditions => "gender = 'm'"}) do
    all_active
  end
end

def self.all_active
  with_scope(:find => {:conditions => "status = 'active'"}) do
    find(:first)
  end
end

# User.all_active
# SELECT * FROM "users" WHERE (status = 'active') LIMIT 1

# User.all_male
# SELECT * FROM "users" WHERE ((gender = 'm') AND (status = 'active')) LIMIT 1
```

We can see that when `User.all_male` is called, it internally calls `all_active`
method and the final sql has both the conditions.

`with_scope` allows nesting and all the conditions nested together are used to
form one single query. And `named_scope` uses this feature of `with_scope` to
form one single query from a lot of named scopes.

## Writing our own `named_scope` called `mynamed_scope`

The best way to learn `named_scope` is by implementing the functionality of
`named_scope` ourselves. We will build this functionality incrementally. To
avoid any confusion we will call our implementation `mynamed_scope`.

To keep it simple in the first iteration we will not support any lambda
operation. We will support simple conditions feature. Here is a usage of
`mynamed_scope` .

```ruby
class User < ActiveRecord::Base
  mynamed_scope :active, :conditions => {:status =>  'active'}
  mynamed_scope :male, :conditions => {:gender => 'm'}
end
```

We expect following queries to provide right result.

```ruby
User.active
User.male
User.active.male
User.male.active
```

## Let's implement `mynamed_scope`

At the top of user.rb add the following lines of code

```ruby
module ActiveRecord
  module MynamedScope
    def self.included(base)
      base.extend ClassMethods
    end

    module ClassMethods
      def mynamed_scope(name,options = {})
        puts "name is #{name}"
      end
    end

  end
end
ActiveRecord::Base.send(:include, ActiveRecord::MynamedScope)
```

Now in script/console if we do User then the code will not blow up.

Next we need to implement functionalities so that `mynamed_scope` creates class
methods like active and male.

What we need is a class where each `mynamed_scope` could be stored. If 7
`mynamed_scopes` are defined on User then we should have a way to get reference
to all those `mynamed_scopes`. We are going to add class level attribute
myscopes which will store all the `mynamed_scopes` defined for that class.

```ruby
def myscopes
  read_inheritable_attribute(:myscopes) || write_inheritable_attribute(:myscopes, {})
end
```

This discussion is going to be tricky.

We are storing all `mynamed_scope` information in a variable called myscopes.
This will contain all the `mynamed_scopes` defined on User.

However we need one more way to track the scoping. When we are executing
`User.active` then the active `mynamed_scope` should be invoked on the User.
However when we perform `User.male.active` then the `mynamed_scope` active
should be performed in the scope of `User.male` and not directly on User.

This is really crucial. Let's try one more time. In the case of `User.active`
the condition that was supplied while defining the `mynamed_scope` `active`
should be acted on User directly. However in the case of `User.male.active` the
condition that was supplied while defining `mynamed_scope` `active` should be
applied on the scope that was returned by `User.male` .

So we need a class which will store `proxy_scope` and `proxy_options`.

```ruby
class Scope
  attr_reader :proxy_scope, :proxy_options
  def initialize(proxy_scope, options)
    @proxy_scope, @proxy_options = proxy_scope, options
  end
end # end of class Scope
```

Now the question is when do we create an instance of Scope class. The instance
must be created at run time. When we execute `User.male.active`, until the run
time we don't know the scope object active has to work upon. It means that
`User.male` should return a scope and on that scope active will work upon.

So for `User.male` the `proxy_scope` is the User class. But for
`User.male.active`, `mynamed_scope` 'active' gets (User.male) as the
proxy_scope.

Also notice that `proxy_scope` happens to be the value of self.

Base on all that information we can now write the implementation of
`mynamed_scope` like this.

```ruby
def mynamed_scope(name,options = {})
  name = name.to_sym
  myscopes[name] = lambda { |proxy_scope| Scope.new(proxy_scope,options) }

  (class << self; self end).instance_eval do
    define_method name do
      myscopes[name].call(self)
    end
  end
end
```

At this point of time the overall code looks like this.

```ruby
module ActiveRecord
  module MynamedScope
    def self.included(base)
      base.extend ClassMethods
    end

    module ClassMethods

      def myscopes
        read_inheritable_attribute(:myscopes) || write_inheritable_attribute(:myscopes, {})
      end

      def mynamed_scope(name,options = {})
        name = name.to_sym
        myscopes[name] = lambda { |proxy_scope| Scope.new(proxy_scope,options) }

        (class << self; self end).instance_eval do
          define_method name do
            myscopes[name].call(self)
          end
        end
      end

      class Scope
        attr_reader :proxy_scope, :proxy_options
        def initialize(proxy_scope, options)
          @proxy_scope, @proxy_options = proxy_scope, options
        end
      end # end of class Scope

    end # end of module ClassMethods

  end # endof module MynamedScope
end
ActiveRecord::Base.send(:include, ActiveRecord::MynamedScope)


class User < ActiveRecord::Base
  mynamed_scope :active, :conditions => {:status =>  'active'}
  mynamed_scope :male, :conditions => {:gender => 'm'}
end
```

On script/console

```ruby
>> User.active.inspect
  SQL (0.000549)    SELECT name
 FROM sqlite_master
 WHERE type = 'table' AND NOT name = 'sqlite_sequence'

=> "#<ActiveRecord::MynamedScope::ClassMethods::Scope:0x203201c @proxy_scope=User(id: integer, gender: string, status: string, created_at: datetime, updated_at: datetime), @proxy_options={:conditions=>{:status=>"active"}}>"
>>
```

What we get is an instance of Scope. What we need is a way to call sql statement
at this point of time.

But calling sql can be tricky. Remember each scope has a reference to the
`proxy_scope` before it. This is the way all the scopes are chained together.

What we need to do is to start walking through the scope graph and if the
previous `proxy_scope` is an instance of scope then add the condition from the
scope to with_scope and then go to the previous `proxy_scope`. Keep walking and
keep nesting the with_scope condition until we find the end of chain when
proxy_scope will NOT be an instance of Scope but it will be a sub class of
ActiveRecord::Base.

One way of finding if it is an scope or not is to see if it responds to
find(:all). If the `proxy_scope` does not respond to find(:all) then keep going
back because in the end User will be able to respond to find(:all) method.

```ruby
# all these two methods to Scope class
def inspect
  load_found
end

def load_found
  find(:all)
end
```

Now in script/console you will get undefined method find. That is because find
is not implemented by Scope.

Let's implement method_missing.

```ruby
def method_missing(method, *args, &block)
  if proxy_scope.myscopes.include?(method)
    proxy_scope.myscopes[method].call(self)
  else
    with_scope :find => proxy_options do
      proxy_scope.send(method,*args)
    end
  end
end
```

Statement User.active.male invokes method 'male' and since method 'male' is not
implemented by Scope, we don't want to call `proxy_scope` yet since this method
'male' might be a `mynamed_scope`. Hence in the above code a check is done to
see if the method that is missing is a declared `mynamed_scope` or not. If it is
not a `mynamed_scope` then the call is sent to `proxy_scope` for execution. Pay
attention to with_scope. Because of this with_scope all calls to `proxy_scope`
are nested.

However Scope class doesn't implement with_scope method. However the first
`proxy_scope` ,which will be User in our case, implements with_scope method. So
we can delegate with_scope method to `proxy_scope` like this.

```ruby
delegate :with_scope,  :to => :proxy_scope
```

At this point of time the code looks like this

```ruby
module ActiveRecord
  module MynamedScope
    def self.included(base)
      base.extend ClassMethods
    end

    module ClassMethods

      def myscopes
        read_inheritable_attribute(:myscopes) || write_inheritable_attribute(:myscopes, {})
      end

      def mynamed_scope(name,options = {})
        name = name.to_sym
        myscopes[name] = lambda { |proxy_scope| Scope.new(proxy_scope,options) }

        (class << self; self end).instance_eval do
          define_method name do
            myscopes[name].call(self)
          end
        end
      end

      class Scope
        attr_reader :proxy_scope, :proxy_options
        delegate :with_scope,  :to => :proxy_scope
        def initialize(proxy_scope, options)
          @proxy_scope, @proxy_options = proxy_scope, options
        end

        def inspect
          load_found
        end

        def load_found
          find(:all)
        end

        def method_missing(method, *args, &block)
          if proxy_scope.myscopes.include?(method)
            proxy_scope.myscopes[method].call(self)
          else
            with_scope :find => proxy_options do
              proxy_scope.send(method,*args)
            end
          end
        end

      end # end of class Scope

    end # end of module ClassMethods

  end # endof module MynamedScope
end
ActiveRecord::Base.send(:include, ActiveRecord::MynamedScope)


class User < ActiveRecord::Base
  mynamed_scope :active, :conditions => {:status =>  'active'}
  mynamed_scope :male, :conditions => {:gender => 'm'}
end
```

Let's checkout the result in script/console

```ruby
>> User.active
SELECT * FROM "users" WHERE ("users"."status" = 'active')
>> User.male
SELECT * FROM "users" WHERE ("users"."gender" = 'm')
>> User.active.male
SELECT * FROM "users" WHERE (("users"."gender" = 'm') AND ("users"."status" = 'active'))
>> User.male.active
SELECT * FROM "users" WHERE (("users"."status" = 'active') AND ("users"."gender" = 'm'))

# you can also see count
>> User.active.count
SELECT count(*) AS count_all FROM "users" WHERE ("users"."status" = 'active')
=> 2
```

`named_scope` supports a lot more things than what we have shown. `named_scope`
supports passing lambda instead of conditions and it also supports joins and
extensions.

However in the process of building `mynamed_scope` we got to see the workings of
the `named_scope` implementation.

## Links

- [Human page](https://www.bigbinary.com/blog/under-the-hood-how-named-scope-works)
