All About ActiveRecord Scopes
Tags: rails, ruby, backend, serverside
Published: 2020-11-23 19:57:27

---
title: All About ActiveRecord Scopes
published: True
description: how to use scopes in your rails app
tags: Rails, Ruby, backend, serverside
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/1tcwiwo2a2xvhk88fstb.jpg
---

**Introduction**

When I started learning Rails, I came across scopes while rummaging google for solutions to several Rails project challenges. During those times, Scopes were terrifying for me at first, and every opportunity I had, I'd sidestep using this incredible concept in any of my Rails projects. 

The fact is that as one proceeds in our different software development journeys, there are some useful concepts and tools that are important to pick up to make our coding experience scale faster. I accepted scope because I later understood what it was all about and how it could help my backend coding journey. 


In this article, I will be explaining what scope is and how to use it in different parts of any Rails application. I have set up an Equipment API with Rails, and this will be the examples utilized as the codebase in this write-up. Check out this [repository](https://github.com/tundeiness/Survey-equipments-api/tree/model) to follow along. Let's dive in. 


**What Are Scopes**

Scopes are SQL queries that you can build in any rails model. Often time, we tend to run similar queries in our rails console to query our database and also understand the structure of the result we are receiving before going further with the development of our applications.
 

According to the official ruby on rails guide, "Scoping allows us to make use of commonly-used queries which can be referenced as method calls on the association objects or models." The general expectation is that all scope bodies should return an `ActiveRecord::Relation` or nil. As a result of this, it makes it easy to call other ActiveRecord methods on it. Simply put, a scope is just a custom chain of active record methods. They are sets of pre-defined queries that can be chained to build other complex Queries.   


**Why use Scopes**

Scopes help you D.R.Y out your active record calls and also keep your codes organized. Scopes make it easy to find the records you need at a particular time. 

Also, using scopes helps us develop a healthy habit of keeping the heavy stuffs away from the controller. Rails convention suggests that implementation of the business logic should exist in Rails model instead of the controller/view. 
 
Scoping also allows you to specify frequently used queries which can be referenced as method calls on the association objects or models.

Furthermore, during testing sometimes, you do not want your test to go into your database to fetch results. With scopes, this is achievable as it allows for easier stubbing. 


**Types of Scopes**

*Default Scopes* **vs** *Named scopes*

Default scopes take the name `default_scope` when defined in the model and, they are scopes that are applied across all queries to the model in question. An example can be seen in the code block below: 

```rb
class Equipment < ApplicationRecord
  has_many :requests
  has_many :customers, through: :requests

  validates :brand, presence: true
  validates :model, presence: true
  validates :equipment_type, presence: true
  validates :serial_no, presence: true
  validates :accessories, presence: true

  default_scope, -> {order("updated_at desc")}
end
```
 
Conversely, named scopes are scopes that take a name and are defined in a model for active record database queries. Typically, a named scope is made up of the `scope` keyword, followed by the name you want to give to the scope, and a lambda. Below is an example of a named scope:

```rb
class Equipment < ApplicationRecord
  has_many :requests
  has_many :customers, through: :requests

  validates :brand, presence: true
  validates :model, presence: true
  validates :equipment_type, presence: true
  validates :serial_no, presence: true
  validates :accessories, presence: true

  scope :not_available, -> {where("available = ?", false)}
end
```

The difference between both examples is glaring: one has a custom name and, one has a statutory name called default_scope. In the above example, the named scope above is called *not_available*. The following arrow sign `->` (lambda) can be re-written as: 

```rb
 scope :not_available, lambda {where("available = ?", false)}
```
note that `->` is replaced with *lambda*. A similar approach can be used with the default_scope as well. 

So in my rails console I can now do this: 
```rb
 equip = Equipment.all
 equip.is_available
```

The lambda is what actually does the query implementation.
It will produce an `ActiveRecord::Relation` object, that contains list of available equipment. 

This also gives us the opportunity to use the created scope in the controller in this manner: 

```rb
  def index
     @equip = Equipment.is_available
     render json: @equip, status: 200
  end
``` 
or

```rb
  def index
    @equips = Equipment.all
    render json: @equips, status: 200
  end

  def availability
    @equip = Equipment.is_available
     render json: @equip, status: 200
  end
```

In the first code block, the route to `index` will always display only available equipment and not all equipment. However, in the second code-block, `index` will display a list of all equipment irrespective of whether it is available or not. Also, `availability` will only display a list of all equipment that is available if I hit the `availability` route. In this way, the controller is being used to decide what information is rendered. When it comes to which scope type to use, please avoid using default_scopes. Want to know why? see this [article](https://dev.to/lewuathe/why-we-should-avoid-defaultscope-in-rails-3ofo)


*Taking arguments*
Named scopes can also take arguments like so: 

```rb
class Equipment < ApplicationRecord
  has_many :requests
  has_many :customers, through: :requests

  validates :brand, presence: true
  validates :model, presence: true
  validates :equipment_type, presence: true
  validates :serial_no, presence: true
  validates :accessories, presence: true

  scope :not_available, ->(bool) {where("available = ?", bool) }
end
```

With the above arrangement, it is now possible to pass parameters from the controller when a request is made to the corresponding route. 

**Using Unscoped**
If you have to work with default scopes, you may need to use the unscoped method to disable all currently applied default scopes. Let's work with an example: 

```rb
  class Equipment < ApplicationRecord
    has_many :requests
    has_many :customers, through: :requests

    validates :brand, presence: true
    validates :model, presence: true
    validates :equipment_type, presence: true
    validates :serial_no, presence: true
    validates :accessories, presence: true

    default_scope -> {where("available = ?", true) }
  end
```
So we can now disable the scope in this manner

```rb
 equip = Equipment.first
 equip.unscoped
```

**What can you do with scopes**

Now let's see examples of what we can do with scopes: 

* **chaining scopes**

we can chain scopes together to build a bigger SQL statement. See the example below:

```rb
   class Equipment < ApplicationRecord
     scope :available, ->{where("available = ?", true) }
     
     scope :available_and_created, -> 
     {available.order(:created_at)}

   end
```

First, we define the scope we want to chain, and then define a second scope. In the body of the second scope, we will chain the first scope and an `ActiveRecord` method to make our query. The chaining can be seen, when we run the kind of query below in the rails console: 

```rb
 Equipment.brand.is_available
```

* **Using Conditionals with scopes**.

The scope named `available`, in the code block below is a typical example of how to use conditionals with scopes. 
 
```rb
   class Equipment < ApplicationRecord
     scope :available,(bool) ->{where("available = ?", 
    bool) if bool.present? }
   end
```
Here we are saying, select all equipment if available is true. 



* **Calling multiple scopes in a class method scope** 


This is achievable by using the `send()`method. 
We can supply several scopes as arguments in the send method and call send on each one. 
The code block below (`chaining`) allows us to dynamically call as many scopes as we want. The code block below is another way of writing scopes and it is called a class method. 
We define a class method with the `self` keyword and it takes an array of arguments called `multiple_method`. This is then supplied to the `send` method in `inject()`. 


```rb
  def self.chaining(multiple_method)
    multiple_method.inject(self, :send)
  end
```

```rb
  Equipment.chaining(["scope_one", "scope_two"])
```

so in the controller we can have this kind of arrangement:

```rb
  def index
    if params[:equipment]
      args = params[:equipment][:multiple_method]
      @equip = Equipment.chaining(args)
    else
      @equip = Equipment.all
    end
  end
```



**Summary & Conclusion**


By now, using scopes should no longer be a difficult task. With scopes, we can easily create SQL queries on the fly. 
Using the equipment API as examples in this article, we can now create a new scope from scratch, chain scopes together, use conditionals in scopes, and supply multiple scopes as an argument in another scope using the send method. The article focused strictly on creating scopes with the lambda approach. Another way to create scope is the use of a class method (which was mentioned when calling multiple scopes as arguments in a scope.).
Found this article to be useful? Please like, share or drop a comment below. You can also reach me via my [twitter](www.twitter.com/tundeiness) handle.  
 



**References**

https://medium.com/@pojotorshemi/ruby-on-rails-named-scope-and-default-scope-74ee3db2a15f

https://devblast.com/b/jutsu-11-rails-scopes

https://jasoncharnes.com/importance-rails-scopes/

https://www.sitepoint.com/dynamically-chain-scopes-to-clean-up-large-sql-queries/