← 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
- Rails 8.1.3 API, named scopes.
- Rails 8.1 Guides, Active Record Query Interface. Cross-checked against the v8.1.3 guide source.
- Rails 8.1.3 API, QueryMethods.
- Rails source, tag v8.1.3, relation.rb, including
_exec_scopeandupdate_all. - Rails source, tag v8.1.3, spawn_methods.rb,
merge. - Rails 8.1.3 API, default_scope and unscoped.