Illustration of a Ruby gem rising on an upward arrow, representing Ruby on Rails version upgrades

A Quick Guide to Ruby & Rails Version Upgrades

blog post publisher

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).
Rails 6 upgrade
new rails version
rails upgrades
rails upgrade services
rails app
rails application
ruby on rails
upgrade ruby 2.7 to 3
upgrade rails

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!

Frequently asked questions

The current stable release is Rails 8.1. Rails 8 requires Ruby 3.2 or newer, with Ruby 3.4 or newer recommended for best performance. If you are on Rails 6 or 7, upgrade incrementally, one minor version at a time, up to 8.1. See our Ruby on Rails work and web development services.
Upgrade one minor version at a time, keep a strong test suite, update your gems first, run rails app:update, review config.load_defaults, and resolve deprecation warnings before moving to the next version. Read the official release notes for each step.
Rails 8 requires Ruby 3.2 or newer. Ruby 3.4 or a newer 3.x release is recommended for the best performance thanks to YJIT improvements.
Upgrading brings security patches, performance gains, new features, and gem compatibility, and it prevents a costly big-bang upgrade later. Staying close to the current release keeps your project secure and maintainable.
Victor Motogna

Written by

Victor Motogna

Head of Web Development

Victor Motogna is the Head of Web Development at Wolfpack Digital, leading the web development team and driving innovation in scalable, secure web applications. With a Bachelor's in Computer Science and a Master's in High Performance Computing & Big Data Analytics, he brings deep technical expertise and a forward-thinking approach to building enterprise-grade solutions.


As both a technical leader and hands-on contributor, Victor works across the full technology stack including Ruby on Rails, Vue.js, Nuxt.js, JavaScript, and Python, with extensive experience in DevOps frameworks and cloud infrastructure (Azure, AWS, Kubernetes). His role extends beyond traditional web development—he plays a key part in architecting AI-powered features, training machine learning models, and ensuring AI integration delivers genuine business value rather than following trends.


Victor's leadership philosophy centers on balancing technical excellence with practical delivery. He excels at translating complex technical concepts into clear business language, architecting solutions that strike the right balance between technical sophistication and MVP speed, and staying ahead of rapid technological change. His approach emphasizes building stable, secure end-to-end solutions while constantly seeking smarter, more efficient development processes.


A frequent speaker at technology conferences across Europe, Victor shares insights on modern web development practices, AI integration strategies, cloud architecture, and building high-performing development teams. His writing draws on real-world experience delivering 250+ digital products and reflects his commitment to using technology to create meaningful solutions that improve people's lives.


Through his blog contributions, Victor explores topics at the intersection of web development, AI, and entrepreneurship, focusing on practical implementation strategies, technology decision-making, and fostering knowledge exchange within development teams.


Areas of expertise: Web application architecture, Ruby on Rails development, Vue.js/Nuxt.js, AI integration, machine learning model training, DevOps and cloud infrastructure, team leadership, full-stack development, technical strategy, scalable systems design.

View profile