← 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

Common synchronous calls in Rails 8.1.3.[1][3][5][7][10]
CallReturn value
where(...), order(...), limit(...)A derived relation
loadThe same relation, with records loaded
to_aAn array of model instances
first without an argumentOne 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

Plain, ungrouped relation with no count block.[4][6][12]
CallUnloaded relationLoaded relation
countNormally runs SQL COUNTNormally runs SQL COUNT
sizeCalls count(:all)Uses the loaded records' length
lengthLoads records and counts themUses 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

  1. Rails API documentation, Relation.
  2. Rails 8.1 Guides, Active Record Query Interface.
  3. Rails API documentation, QueryMethods.
  4. Rails source, tag v8.1.3, relation.rb.
  5. Rails API documentation, Calculations.
  6. Rails source, tag v8.1.3, calculations.rb.
  7. Rails API documentation, FinderMethods.
  8. Rails source, tag v8.1.3, collection_proxy.rb.
  9. Rails source, tag v8.1.3, batches.rb.
  10. Rails source, tag v8.1.3, query_methods.rb.
  11. Rails source, tag v8.1.3, finder_methods.rb.
  12. Rails source, tag v8.1.3, delegation.rb.
  13. Rails source, tag v8.1.3, spawn_methods.rb.