Rails has very good documentation in general and an upgrade guide in particular, but an upgrading task can still be quite tricky and intimidating. None of the documentation covers all the details and sometimes details are the key to overcome challenges that can arise when migrating to a newer Rails version.
I would like to share some tips that I learned from my colleagues and that helped me a lot with developing an upgrade strategy.
The general idea is: before doing Rails update itself, try to update as many dependencies as possible in advance. (Bonus: this strategy can be used for any framework upgrade - for example, I applied this approach when upgrading the application made with Gatsby). The reason is: when you try to upgrade Rails directly, all packages are updated at once as well and you don’t understand where the errors come from. Did a new Rails version cause them? Or some of the gems?
When I once tried to do a Rails upgrade without updating dependencies in advance, all tests were broken. The error message was very weird and not helpful at all. Google and Stackoverflow also did not know about such a problem. I changed my approach and started to update gems one by one. It turned out that the
database-cleaner gem, that our application uses, introduced some breaking changes since our last update (it actually became a set of gems depending on the used database adapters). In our case I had to install a new gem
database-cleaner_mongoid and do some configuration changes. The problem was solved!
So let's have a look how an upgrade to a minor Rails version could be performed (for example, from 6.0 to 6.1). These steps suppose that Rails is pinned to a specific version in your Gemfile, for example
gem 'rails', '~> 6.0.5'.
First of all you could try to update to the next Rails patch version (for example, from 184.108.40.206 -> 220.127.116.11) - this will update only Rails and no other dependencies. In that case you just run
bundle update rails and you are done. You don’t have to run the
The next step would be to run the command
bundle outdated. It lists all outdated gems, pointing to what group each gem belongs to -
test. Then you can update them one by one (you update dependencies only in the
Gemfile, not in
Gemfile.lock). One update - one commit. Do not forget to run tests after each gem update! Some updates are as simple as just running the command
bundle update <gem name>. Others can be more complicated - then it is better to tackle them separately, in a smaller pull requests. For example, the upgrade from
sprockets 3 to 4 requires also some changes in
manifest.js. Or, for example, the
mongoid upgrade to version 7 had some breaking changes, and I had to modify code in several controllers. It is better to not mix up such stuff with other gems updates.
It might seem like a lot of work because the list of dependencies can be pretty long (I ended up with one pull request updating 20 gems plus 4 pull requests for individual gem updates). But at the end of the day it saves you a lot of time since you can discover faster which dependency caused the errors after its update.
Another option to perform Rails upgrades smoothly is to keep your dependencies up to date. You can do it easily by installing dependabot. It will run your pipeline against any new gem updates and you will be able to catch breaking changes early.
Often before the Rails upgrade you would also like to upgrade to a newer Ruby version. Here the same principle is applied: if the upgrade does not work out of the box and you get errors, try to update first those dependencies that block the Ruby upgrade.
Here once again all steps recapped:
- Upgrade Ruby to the latest version compatible with the desired Rails version
- If this does not work, individually upgrade gems blocking the Ruby update, and try again
- Update Rails to the most recent patch version of the currently used release series
bundle outdatedand update all outdated gems one by one
- Perform the Rails upgrade to a minor or a major version following the Rails upgrade guide
- Success! 🎉
Keeping your Rails app up to date is essential. It allows you to use the latest features that will generally make your life easier, and ensures you don't miss important security updates. It'll also keep your developers team happy if they can work with cutting edge libraries!