🔎

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)