
A Quick Guide to Ruby & Rails Version Upgrades
Victor Motogna
Head of Web Development
Reading time: 5 min
Updated: Jun 26, 2026
Key takeaways
- Upgrade Ruby before Rails. Most of the work is making your gems compatible with Ruby 3, and each Rails version sets a minimum Ruby requirement.
- Lean on a strong test suite. Run it after every gem bump, deprecation fix, and the Active Record encryption migration to catch regressions immediately.
- Go incremental, one minor version at a time. The current stable release is Rails 8.1, which needs Ruby 3.2 or newer (Ruby 3.4 or newer recommended).
The example below walks through a Rails 6 to 7 (Ruby 2.6 to 3) upgrade, but the same incremental, test-driven process applies to today's versions. The current stable release is Rails 8.1, which requires Ruby 3.2 or newer (Ruby 3.4 or newer recommended).
We recently upgraded a project from Ruby 2.6.6 to 3.x and Rails 6.0.4.8 to 7.x. The task turned out to be far more demanding than we expected, with plenty of challenges — some better documented than others. So if you're going through something similar, this article covers all the main changes we had to deal with. 🗒️
Short disclaimer: this doesn't cover the under-the-hood changes Ruby and Rails made in their upgrades. Those are widely documented, and we highly recommend these resources: upgrading Ruby and upgrading Rails. Those guides also list some implementation changes you'll need to make. That's our main goal here too — but we'll also cover a few unexpected situations they leave out. To check the latest supported Ruby versions and releases, see this resource.
Let's start with Ruby💎
We started with the Ruby upgrade, and we strongly recommend you do the same. For one, Rails 7 requires Ruby 2.7.0 or newer, and we only had 2.6.6. On top of that, many gem updates depend on Ruby 3 compatibility — so most of the work lives in this upgrade.
Let's get started! 🚀
We use rbenv, so updating the version on our machine was easy. After installing Ruby 3.1.2 (in our case) and updating the project Gemfile, run “bundle install” and then run the tests. Unfortunately, gem incompatibilities show up right away.
That's our first takeaway. If you've had some gem versions locked for more than a year, they're probably incompatible with Ruby 3. You'll likely know which dependencies need updating, but here are three specific examples:
- Rspec-rails - our testing gem of choice. It needed an upgrade to version 5+ on our project.
- Faker - we mostly use this for specs and factories. Upgrading it brought some changes: all methods now need keyword arguments (Faker::Number.unique.number(digits: 2) instead of Faker::Number.unique.number(2)).
- Psych - a bizarre one. There's a very detailed explanation in this Ruby Psych bug report. In short: Ruby 3.0 ships Psych 3, while Ruby 3.1 ships Psych 4, which has a major breaking change. Our fix (at least for the Ruby upgrade) was to add gem ‘psych’, ‘< 4’ to the Gemfile to force a Psych version under 4.x. That also meant changing the machine's default Psych from 4.x to 3.3.2 (gem install --default -v3.3.2 psych) and then following this comment to remove the 4.0.4 version.
Your Gemfile may have many other incompatible gems that you don't use or that sit at a different version. The three above needed the most work on our side and are also the most widely used.
Once we cleared the gem incompatibilities, we had to apply the new Ruby 3 changes to the project. One of the main ones was how positional and keyword arguments now work (more detail in Ruby 3.0's keyword-arguments announcement).
For example, we had let(:params) { key1: ‘value1’, key2: ‘value2’ } and service_base_child.call(params). We had to change it to service_base_child.call(**params).
Finally, we could move to the easy task: updating the Docker and CircleCI images.
Upgrading Rails 🛤️
Our Rails version (and its dependencies) was 6.0.4.8. We'd bumped it a few times since the project started, for security fixes and small changes — but, like with Ruby, those updates were incremental and small. The good news: the Rails upgrade doesn't cause nearly as many incompatibilities, and most changes were syntax, config, or implementation rather than gem updates.
Handily, the Ruby on Rails site has a great guide on upgrading to the current version. We won't repeat what's already there, but some of the smaller steps aren't as smooth as you'd hope. ⚠️
The first step, also in the guide, is updating the Gemfile and the gems, then running rails app:update. This triggers changes across many existing project files. We suggest allowing inserts/updates for all of them, then going through each git diff manually to check the changes make sense. Many are just single quotes becoming double quotes — but expect a few critical ones too. And watch out if the update strips specific settings, like your Action Mailer config.
From the Rails upgrade, we had just five main takeaways to handle. There were smaller changes too, like other gem upgrades, but those are easy to catch and fix.
- In application.rb, set config.load_defaults to 7.0. This loads the default configuration Rails ships for version 7+.
- Move to the new Active Record encryption — meaning you swap anything using attr_encrypted for the new implementation. Luckily, we only used attr_encrypted for a few third-party API access tokens, so we didn't need to migrate database instances — we just deleted them and regenerated them. If you need to keep that data, there are extra steps to consider; this guide explains how. For us, it meant writing a migration to remove the encrypted_access_token and encrypted_access_token_iv columns (required by attr_encrypted) and add a new access_token string. Also, attr_encrypted :access_token, key: :some_key becomes encrypts :access_token. Next, run rails db:encryption:init to generate a set of keys for your credentials. We also found you need to add config.active_record.encryption = Credentials[:active_record_encryption] to each environment file so the app finds and uses these values.
- Replace errors[:base] << 'foo' with errors.add(:base, 'foo').
- If you use bullet like we do, upgrade it to the latest version and make sure no n+1 warnings appear. In our case, the new version caught about 10 cases it hadn't flagged as n+1 queries before. Double-checking those can shave seconds off your next query.
- If you use CarrierWave with attachments, note that attachment.file#filename is deprecated — switch to attachment.file#identifier. Also refactor Kernel#open to URI.open, or better yet URI.parse#open.
Conclusions💡
This upgrade surfaced three key takeaways — and they're why we wrote this article:
- Write tests! Strong test coverage made the job so much easier. Changing methods because of a deprecation, migrating to the new encryption system, upgrading a library? Just run the suite. If everything passes and coverage is good, you can be confident the change worked. Without it, things slip through because “there's nothing new here” — and a validation error still pops up.
- Take your time. This took longer than we expected. You'll hit inconsistencies and incompatibilities that are specific to your project, its previous versions, and its dependencies. After an upgrade like this, test the API or app thoroughly so nothing slips by. In our case, the Kernel#open issue did slip through at first.
- Think about why you're upgrading. As we said, it's a long task. The latest security fixes, bug fixes, and updates are worth having, but major version changes deserve thought. We should all upgrade ongoing projects at some point — just choose the timing carefully.
Thanks for reading, and we hope this guide helps with your own upgrades. We write articles like these whenever we or our community hit unexpected difficulties with no helpful resources around. So if there's a technical problem you're battling, don't hesitate to shoot us a message — we'll do our best to help! 👐
About Wolfpack Digital🐺
With over 250 projects successfully delivered to our partners, we're a web and mobile app development company. Our mission is to bring performance and beauty to the world through technology.
We build projects start-to-end, with deep expertise in beauty app design and development, fintech app development, healthcare IT solutions, custom website development, cross-platform app development, and more.
Have a project in mind? Get in touch, and let's talk!
Ever wondered how to build mobile apps with Ruby on Rails? We wrote an article on that too — give it a read!



