How to Use Scopes in Ruby on Rails

What is a scope in Rails & why is it useful?

Well…

Scopes are custom queries that you define inside your Rails models with the scope method.

Every scope takes two arguments:

  1. A name, which you use to call this scope in your code
  2. A lambda, which implements the query

It looks like this:

class Fruit < ApplicationRecord
  scope :with_juice, -> { where("juice > 0") }
end

As a result of calling a scope, you’ll get an ActiveRecord::Relation object.

Which means you can chain & combine scopes!

Example:

Fruit.with_juice.with_round_shape.first(3)

Now:

There’s more to learn about Rails scopes, so let’s keep exploring the topic.

When To Use Scopes?

Ok, scopes are cool, but when should you use them?

Let’s see an example.

def index
  @books = Book.where("LENGTH(title) > 20")
end

This is an index controller action that wants to display books with titles longer than 20 characters.

It’s fine.

But if you want to use this query in other places, you’re going to have duplicated code.

Duplicated code makes your project harder to maintain.

Let’s move this query into a scope.

Like this:

class Book
  scope :with_long_title, -> { where("LENGTH(title) > 20") }
end

Now our controller action looks like this:

def index
  @books = Book.with_long_title
end

Nice!

How to Use Rails Scopes With Arguments

You may want to introduce a variable into a scope so you can make it more flexible.

Here’s how:

class Book
  scope :with_long_title, ->(length) { where("LENGTH(title) > ?", length) }
end

The question mark (?) is a placeholder, it’ll be replaced by the value of length. This makes your code safer.

If you want a default value:

class Book
  scope :with_long_title, ->(length = 20) { where("LENGTH(title) > ?", length) }
end

Give it a try!

Scope vs Instance Method

Scopes aren’t doing anything magical or super special.

They’re just methods.

In fact… You could do the same thing using class methods!

Like this:

class Fruit
  def self.with_juice
    where("juice > 0")    
  end
end

But there are design advantages to using scopes over class methods.

Here’s why:

  • Scopes result in cleaner code because of their syntax
  • Scopes are used for exactly one thing, so you know what you get the moment you see one
  • Scopes aren’t mixed with other methods, so they’re easier to spot

In terms of functionality, the only difference is that scopes guarantee an ActiveRecord::Relation, and class methods don’t.

This helps you avoid errors when your scope returns nothing.

Don’t Use Default Scopes

A default scope is one which is automatically applied to your model.

Example:

class Post
  default_scope { where(published: true) }
end

Yes!

Default scopes are so attractive.

But they’re often the wrong choice because you’ll probably forget you have them defined, run into strange errors, and waste precious time debugging.

With that said…

If you have to work with default scopes, you may need to use the unscoped method to disable all currently applied scopes.

Watch Video Tutorial

Summary

Good job! As a result of reading this article, you’ve learned how to use Rails scopes in the most effective way.

Don’t forget to put this new knowledge into practice so you can remember how it works.

Thanks for reading. 🙂

Leave a Comment:

6 comments
Alex says last month

Thanks!

Reply
    Jesus Castello says last month

    Thanks for reading 🙂

    Reply
Carlos Urreta says 4 weeks ago

Hey, just wanted to say I really dig your writing style. I read a ton of rails articles but most are not written with clarity in mind. Nice job!

Reply
    Jesus Castello says 4 weeks ago

    Thanks! Clarity leads to understanding 🙂

    Reply
Matvey says 4 weeks ago

Great article, Jesus. As usual! Thanks a lot 😉

Reply
    Jesus Castello says 4 weeks ago

    Thanks for reading!

    Reply
Add Your Reply