← Reference · Nestor G Pestelos Jr · Print this page

Software Development · Ruby on Rails

ActiveRecord Scopes

Reference entry · last updated October 20, 2026

ActiveRecord scopes are named, reusable queries on Rails models. A scope normally returns an ActiveRecord::Relation, which accepts further query methods.[1]

This entry covers Rails 8.1.3. Examples are illustrative and assume a Book model with published, category, created_at, and title columns. They are not measured query logs.

First principles and definitions

A relation describes a query; a model instance represents one record. A scope names a query operation. Calls to where and order compose a relation without loading its records. Enumeration or to_a loads the records.[2][3]

Named scopes and class methods

class Book < ApplicationRecord
  scope :published, -> { where(published: true) }
end

Book.published.order(:title)
author.books.published

scope defines a model class method. Scopes also work on collection associations: the second call retains the association's author condition. The lambda supplies a callable query body.[1]

# Alternative definition, replacing the scope above:
def self.published
  where(published: true)
end

A class method that returns a relation also supports chaining. A method that returns a record, array, or scalar ends relation composition. Scope bodies should return relations; Rails only provides a fallback for nil or false.[1][4]

Arguments and evaluation time

class Book < ApplicationRecord
  scope :in_category, ->(name) { where(category: name) }
  scope :recent, -> { where("created_at >= ?", 7.days.ago) }
end

Book.published.in_category("fiction").recent

Arguments reach the lambda when the scope is called. Expressions inside its body, including 7.days.ago, run at that call. A cutoff calculated outside the lambda can remain fixed while the class stays loaded. Query execution can occur later than scope evaluation.[2][4]

The examples pass values through hash conditions or SQL placeholders. Interpolating untrusted values into SQL strings can introduce SQL injection; naming the query as a scope does not sanitize it.[2]

Conditional scopes and empty results

scope :in_category_if_given, ->(name) {
  where(category: name) if name.present?
}

If a scope body returns nil or false, Rails returns the current relation instead. Existing conditions and default scopes remain. Thus Book.published.in_category_if_given(nil) still selects published books. A plain class method has no automatic fallback.[4]

This fallback means “add no filter,” not “return no records.” none returns an empty, chainable relation. A scope intended to find nothing should return none explicitly.[3]

Combining and changing conditions

Book.published.where(published: false)
# Requires published = true AND published = false

Book.published.rewhere(published: false)
# Replaces the published condition

Chained where predicates combine with SQL AND; a later predicate does not generally replace an earlier one. rewhere replaces conditions for the specified attributes. reorder replaces existing ordering, and unscope(:order) removes it.[2][3]

merge combines another relation's query settings. When both relations contain conditions on the same attributes, the argument's conditions take precedence. It is not interchangeable with appending where conditions.[5]

Author.joins(:books).merge(Book.published)

With a has_many :books association, this reuses the book scope in an author query. The join supplies the related table; merge adds the scope's conditions.[2]

Default scopes

class Book < ApplicationRecord
  default_scope { where(published: true) }
end

default_scope adds query behavior implicitly. Multiple declarations combine. A hash equality condition can also initialize attributes: this example makes Book.new.published true.[6]

By default, its conditions do not constrain updates or deletes on an individual persisted instance. all_queries: true applies its where conditions to those operations. Relation operations such as Book.where(...).update_all(...) still use the relation's conditions.[6][4]

Removing scopes

Book.unscoped.where(published: false)
Book.published.unscope(where: :published)

unscoped starts a relation without previously applied scopes, including default scopes. Its block form temporarily removes them for model queries within the block. unscope removes selected query clauses instead.[3][6]

author.books.unscoped can also remove the association's author condition and expose books belonging to other authors. unscoped is therefore broader than removing one default filter.[6]

See also

References

  1. Rails 8.1.3 API, named scopes.
  2. Rails 8.1 Guides, Active Record Query Interface. Cross-checked against the v8.1.3 guide source.
  3. Rails 8.1.3 API, QueryMethods.
  4. Rails source, tag v8.1.3, relation.rb, including _exec_scope and update_all.
  5. Rails source, tag v8.1.3, spawn_methods.rb, merge.
  6. Rails 8.1.3 API, default_scope and unscoped.