🔎

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 Loading

  • joins — INNER JOIN

  • left_joins — LEFT OUTER JOIN

  • select / 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)