ruby 30 lines · 9 steps

How scopes compose in Rails

A single Article model uses scopes, default_scope, and class methods that chain into composable, reusable queries.

Explained by highlit
1class Article < ApplicationRecord
2 belongs_to :author
3 
4 default_scope { where(deleted_at: nil) }
5 
6 scope :published, -> { where(published: true) }
7 scope :draft, -> { where(published: false) }
8 scope :recent, -> { order(created_at: :desc) }
9 scope :by_author, ->(author) { where(author: author) }
10 scope :published_since, ->(date) { published.where("published_at >= ?", date) }
11 
12 scope :popular, -> { where("view_count >= ?", 1_000).recent }
13 
14 scope :search, ->(term) {
15 return all if term.blank?
16 where("title ILIKE :q OR body ILIKE :q", q: "%#{term}%")
17 }
18 
19 scope :with_comments, -> {
20 joins(:comments).distinct
21 }
22 
23 def self.archived
24 unscope(where: :deleted_at).where.not(deleted_at: nil)
25 end
26 
27 def self.trending(limit = 10)
28 published.popular.limit(limit)
29 end
30end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Scopes are just chainable methods returning relations, so they compose freely into larger queries.
  2. 2default_scope silently filters every query, which is powerful but easy to forget — unscope when you need to escape it.
  3. 3Class methods and scopes are interchangeable for building queries, letting you mix lambdas with conditional Ruby logic.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How scopes compose in Rails — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code