← Reference · Nestor G Pestelos Jr · Print this page
Software Development · Ruby on Rails
ActiveRecord::Relation
Reference entry · last updated October 11, 2026
ActiveRecord::Relation is a Rails object that represents a database query and can hold the model records fetched by that query.[1][4]
This entry covers synchronous queries in Rails 8.1.3, checked against its tagged source. The code uses an illustrative Book model with category, available, and title columns. Examples describe API behavior; they are not measured query logs.
First principles and definitions
A query specifies which rows to retrieve, which columns to return, and how to order or limit the result. A relation stores these choices for one model. Query methods such as where return relations that can accept further query methods.[2][3]
A model instance represents one record. An array holds Ruby objects returned to the application. A relation also carries query operations and a loaded state. It includes Enumerable, so array-like operations are available through record loading.[4][12]
Query composition
fiction = Book.where(category: "fiction")
request = fiction.where(available: true)
.order(:title).limit(3)
These calls build a query without fetching its model records. Ordinary non-bang query methods create a derived relation; the additional condition leaves fiction available as the broader query. The two where conditions combine with SQL AND.[3][10][13]
request.to_sql produces the query's SQL representation without loading the records. Database adapters can produce different SQL text.[1]
Loading and cached records
request.load # loads records; returns the relation books = request.to_a # returns an array of Book objects request.loaded? # true after a successful synchronous load
load fetches and stores records when the relation is unloaded. Later record enumeration on the same loaded relation reuses them. reload clears that state and loads again. Cached records can become stale when the database changes.[4][12]
SQL execution and relation loading are separate events. A count or existence query can return a result without populating the relation's records. Inspecting an unloaded relation in a console can query a limited, derived relation while the original remains unloaded.[4][6][11]
Return types
| Call | Return value |
|---|---|
where(...), order(...), limit(...) | A derived relation |
load | The same relation, with records loaded |
to_a | An array of model instances |
first without an argument | One model instance, or nil |
exists? | true or false |
pluck(:title) | An array of column values |
select(:id, :title) | A relation with a narrower SQL projection |
select { |book| book.available } | An array filtered in Ruby |
count, size, and length
| Call | Unloaded relation | Loaded relation |
|---|---|---|
count | Normally runs SQL COUNT | Normally runs SQL COUNT |
size | Calls count(:all) | Uses the loaded records' length |
length | Loads records and counts them | Uses the loaded records' length |
Blockless count does not use the loaded records as its counting source. The database query cache can serve its SQL result; known-empty relations can short-circuit. count(:title) counts non-null titles, while group(:category).count returns a hash of counts. A count with a block enumerates records in Ruby.[5][6]
exists?, pluck, and select
exists? normally uses a limited existence query without instantiating all matching models. It does not simply read a loaded relation's array. Known-empty conditions can return false without querying.[7][11]
pluck normally fetches selected values without model instances. It can read from a loaded relation when the requested attributes are available. Its array result ends the query chain.[5][6]
Blockless select keeps a relation and chooses SQL columns. A block invokes Ruby filtering after loading. Reading an omitted attribute, except id, raises ActiveModel::MissingAttributeError.[3][10]
Associations and eager loading
A collection association such as author.books returns a CollectionProxy, a relation subclass with association-specific behavior. A loaded collection's size uses its records. Association counting rules should be checked separately from a plain relation.[8]
preload fetches associations through separate queries. eager_load uses LEFT OUTER JOIN. includes normally uses separate queries but can use a join when conditions require it. A joins call alone does not preload association objects.[2][3]
authors = Author.includes(:books).to_a
authors.each { |author| author.books.size }
For the loaded collections in this illustrative example, size uses the preloaded books. Replacing it with blockless count requests a database calculation, even though includes fetched the records.[6][8]
Batching
find_each yields records one at a time after fetching batches. find_in_batches yields arrays, and in_batches yields relations. Batching avoids loading an entire large result into memory at once.[9]
Rails 8.1.3 defaults to an ascending primary-key cursor. A pre-existing relation order can be ignored or rejected. Custom cursor columns need a unique tiebreaker and should remain unchanged during processing. Concurrent database writes can cause race conditions.[9]
Safe query inputs
Book.where(category: params[:category])
Book.where("title = ?", params[:title])
Hash conditions and SQL placeholders keep values separate from the SQL expression. Direct string interpolation of untrusted values can introduce SQL injection. Placeholders do not select safe column names or sort expressions; dynamic identifiers need an application-controlled allowlist.[2][10]
For a literal prefix search with SQL LIKE, sanitize_sql_like escapes user-supplied % and _ wildcard characters before a deliberate wildcard is appended.[2]
See also
References
- Rails API documentation, Relation.
- Rails 8.1 Guides, Active Record Query Interface.
- Rails API documentation, QueryMethods.
- Rails source, tag v8.1.3, relation.rb.
- Rails API documentation, Calculations.
- Rails source, tag v8.1.3, calculations.rb.
- Rails API documentation, FinderMethods.
- Rails source, tag v8.1.3, collection_proxy.rb.
- Rails source, tag v8.1.3, batches.rb.
- Rails source, tag v8.1.3, query_methods.rb.
- Rails source, tag v8.1.3, finder_methods.rb.
- Rails source, tag v8.1.3, delegation.rb.
- Rails source, tag v8.1.3, spawn_methods.rb.