RailsAgency
← All articles

Ruby on Rails

Active Record 8.1 Features Worth Using After 7.2 or 8.0

By Daniel Rice · · 3 min read

Rails 8.1 does not replace the Active Record you already know. If the app is on 7.2 or 8.0, the queries, associations, and migrations still mean the same thing. The new pieces are for the awkward parts: an association you want gone, a table with columns you do not want loaded, a pool that needs a clearer name, and a finder that was quietly unordered.

Rails 8.1.0 shipped on October 22, 2025. The association API is in the release announcement. The rest is in the Active Record changelog.

Mark the association before you delete it

An old has_many is hard to remove because you cannot see every caller. Rails 8.1 lets you deprecate it in place.

class Author < ApplicationRecord
  has_many :posts, deprecated: true
end

Any use of posts is reported. That includes author.posts, assignment, preload(:posts), and nested attributes. The default mode is :warn, with backtraces off. You still get the location of the call. :raise fails the request so a test cannot ignore it. :notify sends the report through the event reporter instead of the logger.

This is the right first week of an association removal. Turn on :warn, ship, read the warnings, then flip the test environment to :raise. Delete the association after the warnings stop, not before.

Load the columns you named

ignored_columns lists what Active Record should skip. only_columns lists what it should keep. The second form is the one you want on a legacy or shared table, where new columns appear that this app does not own.

class Account < ApplicationRecord
  self.only_columns = [:id, :name, :plan]
end

A safe column drop is the other use. Add the column to the "only" list, or ignore it, deploy that, then drop the column in a later deploy. You do not have to guess which running process still selects it.

The pool has the same defaults and clearer names

pool is now also max_connections. The default behavior does not change. Three more settings are available when you do want to change it. keepalive is the number of seconds between checks on a connection that has been idle. max_age is how long a connection may exist before the pool retires it at the next check-in. min_connections is how many connections the pool keeps open.

Leave them unset until a real incident says the pool is the problem. Renaming pool in database.yml is optional. Reading the new names in the guides is enough, so the next person does not think max_connections is a second pool.

Shards, isolation, and one PostgreSQL error

Shard keys can be integers, not only symbols.

ActiveRecord::Base.connected_to(shard: 1) do
  Account.find(params[:id])
end

ActiveRecord.with_transaction_isolation_level sets the isolation level for every pool touched inside the block, and leaves the pools you never touch alone. Use it around the action that needs a stricter read, not around the whole process.

PostgreSQL exclusion-constraint failures now raise ActiveRecord::ExclusionViolation, so a rescue can target that constraint instead of every statement error.

Two events, and a finder that should have had an order

Active Record emits structured events named active_record.sql and active_record.strict_loading_violation. If you already subscribe to Rails.event, SQL and strict-loading violations show up as events with a payload, not as a line you have to parse. The subscriber shape is the same one from the Rails 8.1 event reporter.

first and last without an order are deprecated when the model has nothing to fall back on: no implicit_order_column, no query constraints, no primary key. Rails 8.1 adds a framework default that will raise, and the old silent behavior is deprecated with the setting aimed at removal in 8.2. An unordered first was always a race with the query planner. Put an order on it, or stop calling it.

schema.rb now lists columns alphabetically. That is a one-time diff when you upgrade. Review it as noise, then commit it, so later migrations are readable.

What we turn on first

From 7.2 or 8.0, the upgrade is still the Rails upgrade you already know how to run: boot, migrate, test, read the deprecation log. The new Active Record APIs are opt-in. The one that pays for itself on an old schema is deprecated: true on the association everyone is afraid to touch, and an order on every first the deprecation log names.

Rails Agency will do that pass on the upgrade, turn the warnings into a list, and leave the pool settings alone until a graph says they matter.

FAQ

Do I have to rename pool to max_connections on the upgrade?
No. pool still works and the default behavior is unchanged. Use max_connections when you set the new options, and do not set both keys to different values.

Dealing with this in your own Rails app?

Book a free 30-minute call. You'll talk directly to a senior Rails engineer — no sales team, no hand-offs.