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:
- A name, which you use to call this scope in your code.
- 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 Class 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. 🙂