🔎
Scopes & Query Interface
再利用可能なクエリに名前を付けて管理
Scopeはよく使うクエリ条件をモデルに名前を付けて定義する機能です。
class Post < ApplicationRecord
scope :published, -> { where(status: 'published') }
scope :recent, -> { order(created_at: :desc) }
scope :by_author, ->(user) { where(user: user) }
scope :this_month, -> { where(created_at: Time.current.beginning_of_month..) }
end
使用:
Post.published # publishedポストのみ
Post.published.recent # チェーン
Post.published.by_author(user).recent # 複数scope組み合わせ
Post.published.count # 集計との組み合わせ
Query Interface主要メソッド:
where— 条件(AND)or— OR条件not— NOT条件order— ソートlimit/offset— ページングincludes— Eager Loadingjoins— INNER JOINleft_joins— LEFT OUTER JOINselect/pluck— 特定カラムのみ取得
クエリはLazy Loadingで、実際にデータが必要な時点でのみSQLが実行されます。
キーポイント
1
scope :name, -> { where(...) }でスコープ定義
2
Model.scope_nameで呼び出し(クラスメソッドのように動作)
3
複数scopeをチェーンして複雑なクエリ構成
4
引数が必要なscope: scope :by_status, ->(s) { where(status: s) }
5
default_scopeは全クエリに自動適用(注意して使用)
6
Lazy Loading: .to_a、.each、.count等の呼び出し時点でSQL実行
メリット
- ✓ コード再利用(DRY)
- ✓ 可読性向上 — クエリの意図が明確
- ✓ チェーンで柔軟な組み合わせ
- ✓ Lazy Loadingで不必要なクエリを防止
デメリット
- ✗ default_scopeは予想外の動作を引き起こす
- ✗ 過度なscopeはコード追跡が困難
- ✗ 複雑なクエリはSQLの方が明確な場合がある
- ✗ scope内のside effectに注意
ユースケース
状態別フィルタ(published、draft)
日付範囲フィルタ(this_week、this_month)
ソート(recent、oldest)
ユーザー別フィルタ(by_author)