The go-to resource for upgrading Ruby, Rails, and your dependencies.

Fix Broken CI Builds from Rails 7.1 Deprecation Warnings


In 1852, Boston installed the world’s first municipal electric fire alarm system. The concept was straightforward but revolutionary: distribute telegraphic pull boxes across the city so that when a fire broke out, a signal would be immediately transmitted to a central station. This system’s purpose was to provide an immediate, unambiguous signal that something was wrong, enabling corrective action before a small issue escalated into a widespread disaster.

Similarly, our Continuous Integration (CI) builds act as the early warning system for our software. When we execute a Ruby on Rails upgrade — particularly a migration to a new version like Rails 7.1 — our CI pipeline will likely flash red. This does not necessarily mean our application is fundamentally broken, but rather that the framework is signaling that our code relies on patterns slated for removal.

For large and complex applications, these deprecation warnings can quickly overwhelm the build output, failing tests and blocking feature development. The alarm is ringing, but how do we quiet it without ignoring the fire?

The Mechanics of CI Failure During Upgrades

Why exactly do deprecations break a build? Strictly speaking, a deprecation warning is text output to standard error. In a vacuum, it won’t stop your application from running.

Many engineering teams, however, configure their test environments to treat deprecations as fatal errors. In a typical Rails application, you will find this managed in your configuration files:

# config/environments/test.rb
config.active_support.deprecation = :raise

This configuration is excellent for technical debt remediation, as it forces us to address outdated patterns immediately rather than letting them fester. The challenge, though, is that a major framework bump introduces dozens of new deprecations simultaneously, transforming a useful safeguard into an impenetrable wall of red CI failures.

A Phased Workflow for Remediation

When deciding how to upgrade a Rails app, the instinct is often to fix every warning in a single, massive pull request. This approach is risky and time-consuming. A more sustainable workflow involves a phased remediation strategy.

Before you begin addressing these deprecations, though, it is wise to ensure your test suite is fully passing on your current version of Rails. This provides a stable baseline to measure your progress against.

First, let’s discuss a few possibilities for managing the noise. There are three major approaches to handling these warnings:

The first is to temporarily change the deprecation behavior to log or silence during the initial upgrade phase. This allows us to isolate actual test failures from mere warnings. While this gets the build green faster, it defers the technical debt remediation entirely, masking the true state of our codebase.

The second is to utilize a dual-booting strategy. By using a tool like the bootboot plugin for Bundler, our team can incrementally fix warnings against Rails 7.1 while the main branch continues to run smoothly on Rails 7.0.

The third is to systematically target the most prevalent warnings first, while leaving :raise enabled for the rest of the test suite.

Generally speaking, the dual-booting approach combined with systematic targeting is my preferred method. Dual-booting provides a safe sandbox for exploring the upgrade’s impact without disrupting ongoing feature work. Once we have our CI environment configured to dual-boot, we can begin addressing the specific deprecations.

Let’s examine three of the most common offenders in Rails 7.1 that will break your CI build, and how to resolve them.

1. The show_exceptions Configuration

Historically, Rails allowed you to configure how exceptions were handled in different environments using boolean values. You will likely find this line in your application’s config/environments/test.rb file:

# The old way
config.action_dispatch.show_exceptions = false

In Rails 7.1, using true and false values for config.action_dispatch.show_exceptions is deprecated. This is one of the first things that will break your test suite upon upgrading. The framework now expects a symbol representing the specific behavior: all, rescuable, or none.

One may wonder: why did Rails deprecate boolean values for this configuration? The answer is straightforward: booleans lacked the nuance required for modern application testing. By moving to symbols, the framework allows for more granular control over error handling.

To fix this deprecation, you should update your configuration to use the appropriate symbol:

# The new way
config.action_dispatch.show_exceptions = :none

For your production environment, you will typically change true to all.

Note: The rescuable option is particularly useful if you want to test how your application behaves when handling ActiveRecord::RecordNotFound or similar exceptions that are conventionally rescued by the framework, without showing exceptions for every other error type.

2. The Rails.application.secrets Deprecation

For years, the secrets.yml file was the standard method for storing application configuration. However, Rails has been moving steadily toward encrypted credentials. In Rails 7.1, the usage of Rails.application.secrets is officially deprecated.

If your CI build relies on reading from secrets.yml during test setup, you will see immediate failures:

DEPRECATION WARNING: `Rails.application.secrets` is deprecated and will be removed in Rails 7.2.

If your code looks like this:

# The deprecated way
api_key = Rails.application.secrets.stripe_api_key

You have two practical paths forward. The recommended approach is to migrate to Rails.application.credentials, which provides encrypted, environment-specific credential management out of the box.

# The new way using credentials
api_key = Rails.application.credentials.stripe_api_key

If your infrastructure relies heavily on environment variables (as is common in Twelve-Factor applications), you might bypass Rails credentials entirely and use ENV or a gem like dotenv.

3. The ActiveSupport::Deprecation Singleton

In older versions of Rails, if you were writing a RubyGem or a custom internal library and wanted to issue a deprecation warning, you would typically use the global ActiveSupport::Deprecation singleton:

# The deprecated way
ActiveSupport::Deprecation.warn("This method is outdated.")

Global state, of course, introduces complexity. Rails 7.1 deprecates the usage of this singleton in favor of instantiating isolated deprecator objects. This ensures that your deprecation configurations don’t bleed into other libraries or the framework itself.

We can see this isolation in action by jumping into a Rails console and testing our new deprecator:

$ bin/rails console
irb(main):001> my_deprecator = ActiveSupport::Deprecation.new("2.0", "MyLibrary")
=> #<ActiveSupport::Deprecation ...>
irb(main):002> my_deprecator.warn("This method is outdated.")
DEPRECATION WARNING: This method is outdated. (called from (irb):2)
=> nil

By explicitly creating a deprecator for our library, we control its behavior independently of the rest of the application. If your application code or internal engines are using the singleton, you will need to replace them with custom deprecator instances.

Maintaining Long-Term Technical Health

Fixing these warnings systematically improves the technical health of your application and reduces security risks associated with outdated dependencies. Of course, identifying and resolving every deprecation manually is time-consuming, especially when balancing product development against infrastructure needs.

Ultimately, technical debt remediation is rarely glamorous, but it is necessary for the long-term sustainability of any software project. By addressing Rails 7.1 deprecation warnings methodically — rather than viewing them as an annoyance to be silenced — we ensure a robust foundation for our application’s future. The fire alarm, after all, exists to empower us to put the fire out before the structural damage becomes irreversible.

Sponsored by Durable Programming

Need help maintaining or upgrading your Ruby on Rails application? Durable Programming specializes in keeping Rails apps secure, performant, and up-to-date.

Hire Durable Programming