Can You Upgrade Rails in Increments?
Ruby on Rails is a powerful web application framework that has evolved over the years, with new versions bringing in features, improvements, and security updates. As your application matures, keeping it up-to-date with the latest Rails version becomes crucial. However, the prospect of upgrading an entire Rails application can be daunting. In this blog post, we’ll explore whether it’s possible to upgrade your Rails application in increments and how to go about it.
First, you may be wondering - what does it mean to upgrade in increments?
There are two ways you can interpret “increments”. I will cover both interpretations below.
Say you want to upgrade from Rails 5 to Rails 7. Instead of jumping directly to Rails 7, you might first upgrade to Rails 5.1, then to Rails 5.2, and so on, until you reach the desired version. The Rails Upgrade Guide always recommends this approach of upgrading Rails one minor version at a time, which is the recommendation we follow here at FastRuby.io. There are simply too many changes between minor versions, let alone between major versions, to make skipping versions a good idea.
Now that we got that caveat out of the way, let’s talk about what this article is really about: can you upgrade between minor versions in increments? The short answer is yes. While we have done focused upgrades for many of our past clients, by that I mean working with a client for a short amount of time to focus solely on the upgrade, it’s not the only way to do an upgrade. In our fixed-cost monthly maintenance service , we work with clients to progressively pay down tech debt, including upgrading Rails versions in increments.
While the process is the same no matter the timeline, here are a few reasons why you might want to upgrade in increments:
- Not as disruptive to feature development workflow
- Allows you to identify and address issues incrementally, reducing the overall risk associated with a major upgrade.
- If your application has a significant amount of custom code or if it diverges significantly from typical Rails conventions, a gradual upgrade may be more practical as it allows you to address specific issues in your custom code incrementally.
Now that you know the benefits of upgrading in increments, you might be wondering how to best approach the process. Here’s the way I would approach the incremental upgrade process:
- Plan your upgrade
- Get prepared technically before attempting the upgrade process
- Upgrade Ruby, if desired
- Work through the upgrade process in steps
Plan your upgrade
Create a plan for your upgrade before you start. Do you want to upgrade just one minor version? Or do you plan to do multiple major Rails jumps? Would you want to upgrade Ruby as well? The Rails Upgrade guide also suggests, as we do, to upgrade Ruby first, if needed, before you upgrade Rails. Here’s our compatibility table to check if you also need to do a Ruby upgrade.
Get prepared technically
There are several things you can do to get prepared. The most important step you can take to get prepared is to have a robust test suite. What do I mean by a “robust test suite”? In our experience, we have found that the most successful upgrade projects have at least 70% test coverage with few flaky tests .
But don’t fret if that doesn’t apply to you - you might just have to do more manual QA to ensure things are working smoothly. Our article 10 strategies for upgrading Rails applications with low test coverage has some strategies to use if you’re facing an upgrade with low test coverage.
Two steps that are not as important, but will make the upgrade process easier, are to upgrade dependencies and to track deprecation warnings. These two items are not essential because you will tackle each of these things during the upgrade process.
Tracking deprecation warnings
There are two main ways to get deprecation warnings applicable to your codebase. The first way is to ensure that you are setting your deprecation notices to print out when you run your tests. Then you can run your test suite and gauge how many deprecation warnings you have that way. This might not work so well if you don’t have a robust test suite.
The second way to get deprecation warnings is to set up a deprecation warning tracker in production, which you can learn how to do in our article The Complete Guide for Deprecation Warnings in Rails .
Upgrade dependencies
My article How to Delay a Rails Upgrade gives you some tips on how to how to evaluate the current state of your Rails dependencies. When you’re upgrading dependencies, make sure that your updated dependencies work in both your current and your target version of Rails.
Upgrade Ruby, if needed
As mentioned above in the ‘Plan your upgrade’ section, a Ruby upgrade might be necessary depending on whether you are already using the Ruby version required for your target Rails version. If a new Ruby version is needed, we’ve got you covered. Read through the below section to learn how to approach the upgrade - here at FastRuby.io we approach the Ruby upgrade the same way as the Rails one. We also have a separate guide to help you upgrade Ruby .
Work through the upgrade in steps
We have written about this process many times (we even have a book !) Our upgrade process is roughly the same for every upgrade we do, no matter whether it’s done all at once or in increments:
- Fix deprecation warnings for the current version
If you followed my instructions earlier, you should have a list of these deprecations either from CI or through your deprecation warning tracker. Fix these first and incorporate them into your main
branch.
If you are upgrading incrementally, you probably aren’t going to be able to fix your deprecations all at once. One thing you can do is to commit to fixing a certain number of deprecations over an amount of time (per sprint, per month, etc.) That number is going to depend on your specific project - the number of deprecations that exist and the complexity of each deprecation’s fix. When we do incremental upgrades here at FastRuby.io, we tend to prioritize - for instance, fixing the deprecations that appear the most in our client’s deprecation warning trackers and/or CI.
Once you finish fixing all instances of a deprecation warning, I would add safeguards to avoid re-introducing that deprecation regression. We have an article to help you add those safeguards to avoid deprecation regressions .
- Dual boot current and next versions of Rails
If you’ve read any of FastRuby.io’s articles before, you know that we favor the dual boot technique to run both the current and the target Rails version locally/ and in CI. Using conditionals, you can fix code that breaks in the next version of Rails while keeping the current version working as expected.
Now that we are using the dual boot technique, the next two steps should be fairly straightforward:
- Upgrade any gems/libraries that are not compatible with next version of Rails
- Fix test failures in the next version of Rails, ensuring that the current version of Rails works as expected
Once both sets of test suites are green, it’s time to wrap up the upgrade process:
- QA next version of Rails
- Use next version of Rails in production
Once the upgrade is finally done and the next version is being run in production, it’s time to finish the upgrade process - remove dual boot code and run post-upgrade tasks. We have an article to help you with that process:
Conclusion
While it’s not the only way to upgrade, Rails upgrades can definitely be completed in increments. Upgrading in increments is a great way to address technical debt while still continuing day to day software development tasks.
Need help upgrading your Rails application? Talk to us today!