Mastering Rails Scopes
From Chai to Chaining: A Fun Guide to Rails Scopes
Hello, there! Ever felt like your model queries are a big, tangled mess? Well, don’t worry. Scopes are here to be your personal query superheroes. Think of them as your go-to spice mix for that perfect curry: quick, easy, and always effective.
What is a Scope?
Scopes are just like ordering from a menu card from a restaurant for your Rails models. Define them once, and then you can use them anytime. No need to cook up the same query from scratch every time!
Here’s how you create and use the scope:
class User < ApplicationRecord
scope :active, -> { where(active: true) }
scope :recent, -> { where('created_at >= ?', 7.days.ago) }
end
User.active # Finds all active users. Like finding all your friends online.
User.recent # Gets users who joined in the last week. Fresh and hot, just like that samosa.
Chaining Scopes: The Ultimate Combo
Want to create a super query? You can chain scopes together like mixing your favorite dishes. It’s like ordering a dosa with extra chutney and sambar: the perfect combo!
User.active.recent # Even though User.active returns empty set, the later query won't throw any exception
This fetches all active users who joined in the last week. When you chain scopes like User.active.recent
, if User.active
returns an empty set, the subsequent query won't throw an exception. Instead, it will simply return an empty set.
Scopes with Parameters: Add Your Personal Twist
Sometimes you need a little extra spice. Scopes with parameters let you customize your queries just like adding extra chili to your curry.
class User < ApplicationRecord
scope :created_after, ->(date) { where('created_at > ?', date) }
end
# Usage
User.created_after(30.days.ago)
Now you can find users who joined after a specific date.
Scopes vs. Class Methods: The Showdown
So, which is better, scopes or class methods? Think of scopes as your trusty kitchen gadgets that make cooking a breeze, and class methods as the old-school tools that require a bit more grease.
Class Method:
class User < ApplicationRecord
def self.active
where(active: true)
end
end
- Class methods can handle queries or perform simple string manipulations (it can be a query or no query)
- For conditional logic, class methods often involve more complex code and can’t usually be written in just one line (except the ternary operator)
- Class methods don’t support default methods, so every method call needs to be explicitly defined
- Class methods don’t support chaining like scopes do, but you can use them with conditional operators like
&
to combine results
Scope:
class User < ApplicationRecord
scope :active, -> { where(active: true) }
end
- Scopes are used to handle common queries such as ordering and filtering (not for string interpolation so definitely some query)
- Because scopes utilize lambdas, you can easily add conditional logic in a single-line
- Scopes allow for the use of a default scope, applying a set condition automatically unless specified otherwise
- Scopes are especially useful for chaining methods together, making them a popular choice for combining multiple query conditions
Scopes are usually preferred because they’re neat, concise, and let you chain queries effortlessly. While more flexible, class methods might require a bit more manual effort.
Default Scopes: Always on the Menu
You can set a default scope for a model, making it the default dish served every time. But be careful, it’s like having too much of a good thing.
class User < ApplicationRecord
default_scope { where(active: true) }
end
User.all #=> returns only active users
With this default scope, every query will assume users are active unless you explicitly say otherwise. Just like assuming your dosa comes with sambhar unless you ask for plain.
Override Default Scope:
User.unscoped # Skip the default scope
Alternatively, we can have two separate scopes as below,
class User < ApplicationRecord
default_scope { where(active: true) }
scope :including_inactive, -> { unscope(where: :active) }
end
# Usage
User.all #=> returns only active users
User.including_inactive #=> returns active and inactive users
Summary
For those days when you need to handle large datasets, scopes help you manage them efficiently. Scopes are your new best friend in Rails, they make your queries cleaner, more manageable, and easier to reuse. So go ahead, embrace them, and make your Rails applications as delightful as a well-made masala dosa.