June 19, 2016
Rails 5 is nearly here! But you're dreading the upgrade process. Fear no more, friend: this guide has you covered. This year, I was fortunate enough to attend RailsConf in Kansas City, including the Keep Rails Upgraded workshop by Derek Prior, Caleb Thompson, and Richard Schneeman. As someone relatively new to Rails, they swiftly took me from never having upgraded Rails versions to feeling totally comfortable updating my apps in production.
Depending on the size of your app, this isn't intended to be a particularly short process. You'll be reading gem changelogs, wrestling with deprecation warnings, and waiting patiently for your Rubygems dependencies to resolve. But it's really not as hard as it seems! Also, while this guide is written with Rails 5 in mind, the rules are general enough to guide you through any version upgrade.
I'll be using Derek Prior's lobsters repo for my example, which is what they used in the RailsConf workshop. Feel free to follow along by cloning the repository and starting at the master branch!
0. Begin Anew (Branch)
Before you really get started, create a new git branch for your work. You may be inclined to think, “Oh, but I'm only upgrading to 5 from 4.2.6. I'll be fine!” 12+ attempted (and failed)
later, you'll realize that you were very wrong. Do keep in mind that you'll want to keep as much of your progress in your main branch as possible, so don't be afraid to merge your new branch into your base branch for any of the work you do in step 1.
1. Start with a Clean Test Suite
Yes, all of your tests should be passing. But that's not all! You also shouldn't have any deprecation warnings while your test suite runs. (Otherwise, something will break during the upgrade process!) If you're upgrading to Rails 5 from 4.2, you'll see warnings for anything that will be unsupported or removed in 5.0 while running your current 4.2.x test suite. Ideally you'll also be starting with all or most of your gems up to date, which will make the process much easier.
2. Bundle Update
Now that you're prepared, it's time for the exciting part! Go ahead to update your Gemfile specifying the newest Rails version. At time of writing, that's:
gem 'rails', '~> 5.0.0.rc1'
And now, switch over to the shell and run
$ bundle update rails
3. Don't Panic
You're going to see some error messages like this:
But this is totally normal and expected. We're conditioned to think the worst when we're doing a routine
and things come to a screeching halt with red text, but this is what you've been waiting for! You now have an actionable step to take on your road to upgrade.
So, what's bundler trying to say here? The first line tells us that different gems we depend on require different versions of railties. I looks like jquery-rails and rails itself are simpatico in wanting newer versions, but the version of rspec-rails we're currently using, 3.4.2, is looking for a version of railties that's
4. Update the Offending Gem
If we go over to the rspec-rails Rubygems page, we'll see that there's a new version available:
Looks like this version depends on
railties >= 3.0.
The most recent version we'll need is
so this version of rspec-rails is compatible! Just specify the new version in your Gemfile:
gem 'rspec-rails', '~> 3.5.0.beta4'
will accept multiple gem arguments, you can run
$ bundle update rails rspec-rails
to try again.
5. We're Still Not Panicking
This time, it looks like exception_notification is the problem because of an actionmailer conflict.
To Rubygems! Wait…
Oh no! It looks like the version we're using of exception_notification is the latest. Never fear, this is fixable as well. We'll head on over to their GitHub repo…and they have a dedicated
branch (with associated PR
In our Gemfile, we'll use this branch specifically, instead of the latest Rubygems release:
gem 'exception_notification', github: 'smartinez87/exception_notification', branch: 'rails5'
and try to
$ bundle update rails rspec-rails exception_notification
6. Success! …Right?
Ah, the two sweetest words in Rails development:
The hardest part's over! Now's a great time to commit your progress. I'll wait.
…Okay, now that you've commited (on a dedicated upgrade branch!), we want to make sure nothing broke in your app. Go ahead and run your test suite.
Yikes, it looks like we've got a bit going on here.
7. Make Your Tests Pass
Of course, the most important thing here is that tests are failing. Let's make those pass immediately! We'll want to take look at the
files to see what's wrong.
Hint: on line 13 of
But if we look in the Utils model, that's an instance method! We can edit the EmailParser to use
Boom! Our tests are passing. Now, about those pesky deprecation warnings…
8. Deprecation Warnings, Be Gone!
Thankfully, all of these deprecation warnings have very useful messages. Take this for example:
When we go directly to the named file and look for
we can delete the line containing it and paste the suggested code in its place.
Since all the warnings we have are accompanied by very helpful messages, we can repeat this process for each one until they're all fixed.
Note: if you're upgrading a different app and can't find the ultimate source of your deprecation warning (maybe it's being called in your
file, which you haven't touched), do some Googling around. You're not the only person trying to make this same upgrade, and one of your dependencies may have an issue filed for the error.
Now, run the test suite again and…
9. Celebrate! 🎉
Passing tests and no deprecation warnings! We did it! We upgraded to Rails 5! And it really wasn't that bad.
Takeaways (and Advice for More Complex Upgrades)
Above all, it's most important in this process to remember that you're in control of what's happening. Yes, your large-scale production app will be more difficult to upgrade than the example used here. But that's okay! Some other things to keep in mind while upgrading:
- If your gems are severely out of date, say, a new major version has been released since you last checked on it, make sure you read the changelog before updating. There could be breaking changes in the new version that you'd prefer to know about beforehand!
- When updating gems, if you're updating to a pre-release version like a beta or release candidate, you must explicitly specify this in your Gemfile. Otherwise, Bundler assumes you want the latest official build.
With a more complex app with lots of dependencies, you're going to need to repeat steps 3-5. A lot. Don't get discouraged; this is normal. If you find yourself chaining a ridiculously long list of apps in one
bundle updatecommand, break it up into chunks, starting with the least-offensive gems and working your way up to bigger ones (if you're using refinerycms, good luck). Commit your progress along the way to keep everything tidy and manageable.
- Finally, if you're looking for specific Rails 5 upgrade advice, the slide deck from the RailsConf workshop has a lot of great tips of some of the bigger changes most likely to trigger deprecation warnings or test failures.
Don't you feel better now? And so accomplished! If you've got any questions, please feel free to contact me. Happy upgrading!