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. 🙂
Thanks!
Thanks for reading 🙂
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!
Thanks! Clarity leads to understanding 🙂
Great article, Jesus. As usual! Thanks a lot 😉
Thanks for reading!
In the section title “Scope vs Instance Method”, did you mean “Scope vs Class Method” ?
Yes! 🙂