blog

Ruby On Rails Upgrades

Ten Steps To Take Before Starting a Project

“The Web as I envisaged it, we have not seen it yet,” said Tim Berniers-Lee, the inventor of the world wide web. “The future is still so much bigger than the past.”

He said that in 2009 – since then, the web grown substantially with no clear end in sight.

Unsurprisingly, tools for dealing with this complexity continue to be developed – but when a new and fancy version comes out, all of the code written for previous versions continues to exist. Ruby on Rails is a great example: once, it is was the industry darling, new and exciting. These days, though, Rails is a mature web framework – one that still receives major updates.

The question, therefore, how can you make a Ruby on Rails upgrade project go smoothly?

It’s a good question. After all, Rails upgrades can be daunting – but at Durable Programming, we have a lot of very specific experience.

Here are ten steps to take before embarking on your Rails upgrade journey.

Step 1: Assess Your Current Version

Know where you’re starting from. Check your Rails version and make note of how many major versions behind you are.

TIP: Rails, like most Ruby projects, uses semantic versioning. This means that 1.2.3 would be major version 1, minor version 2, and patch version 3.

Major versions are typically the most difficult, with minor versions having some breaking changes, but usually simpler. In most cases, you can upgrade to a later patch version without much difficulty.

When planning your target upgrade version, keep a close eye on future releases; what is current today may be aging tomorrow. You can check the current supported release series at the RubyOnRails.org site:

https://guides.rubyonrails.org/maintenance_policy.html

Even while planning an upgrade, it may be wise to begin planning for the next upgrade. How long do you expect to go before upgrading to the next version? Can you slot it onto your dev calendar now?

Step 2: Catalog Your Customizations

Make a list of any monkey patches you’ve added. These are likely to break during the upgrade, and will need special attention.

Are any of these customizations replaceable by Rails features? If not, can they be replaced by a Gem or other functionality? In many cases, it’s easier to remove old monkeypatches and replace them with a more mainstream approach than it is to re-write them for a later version of Rails.

Step 3: Evaluate Your Test Coverage

Automated testing is crucial for a smooth upgrade. Assess the coverage and quality of your existing test suite. Improve it if necessary before proceeding. Although its quite possible to proceed without a fully functioning test suite, it is more difficult, and can make troubleshooting quite nettlesome.

If you proceed without a fully functioning test suite, its important to note what portions are functioning before the process begins. In some cases, developers have spent much time trying to debug test failures “caused” by a Rails upgrade – whereas, in fact, the tests were broken or intermittently failing to begin with!

Some older Rails projects have dependencies on test order – since this may change in the upgrade, and indeed its common for newer Rails projects to use randomized test order, note carefully if your tests can be run out-of-order or not, and if they can be run partially or not.

Step 4: Set Up a Staging Environment

Create a dedicated staging environment to perform the upgrade without affecting production. If you already have a staging environment, consider setting up a dedicated environment for the Rails upgrade branch; it is not uncommon to need to test and release software during a Rails upgrade. Do your best to keep your staging environment as similar to production as possible.

Step 5: Choose an Upgrade Strategy

Decide between a “all-in” approach (upgrading directly to the latest version) or an incremental approach (upgrading one or two versions at a time). Consider the size and complexity of your app. Incremental approaches often take more overall time, but can also work more smoothly with parallel development on your main codebase.

Step 6: Create a Detailed Upgrade Process Map

For example, you may wish to split the upgrade process into manageable milestones: fixing Gemfile conflicts, then passing unit tests, then functional tests, then integration tests, then testing your system manually by some functional unit.

Step 7: Notify Your Stakeholders

Communicate the upgrade plan and timeline to all relevant parties, such as dev team, leadership, customers, etc. Set expectations around downtimes or maintenance periods.

Step 8: Practice, practice, practice.

Often, the deploy process will involve a number of pieces; it may also require system administration changes, datastore upgrades, data changes, and so forth. Plan on practicing the entire process – or, at least as much as is reasonable. For example, you may take an extra server and run the entire deploy routine on a copy of the live data set – which will give you an example of what kinds of problems can expected. Many upgrade projects have been derailed by crashes relating to differences between development, staging, and production – and that’s something you can minimize or even avoid altogether with careful rehearsal.

Step 9: Have a Rollback Plan

Despite our best efforts, issues can arise. Write a detailed a plan in place to roll back the upgrade if critical problems are encountered, including:

  • What backups need to be taken prior to the deploy to ensure rollbacks can happen?
  • Are any data migrations irreversible?
  • Determining the “point of no return” where the upgrade can’t be reverted.
  • If moving to a new cluster, cloud, server, or location, at what point can the old resources be freed or reused?
  • What monitoring needs to be in place during the transition period?
  • Who makes the revert/no-revert decision?
  • If the decision is made to revert, who will implement the decision?

Step 10: Relax

Although upgrade projects can be daunting, they are, in the end, just a series of hurdles to overcome. To be sure, it can be many hurdles, but many are relatively straightforward changes. After finalizing an upgrade plan, relax for a moment – once you have the path mapped out, all you have to do is keep going one step at a time.

Conclusion

By following these ten prep steps, you’ll lay a solid foundation for a successful Rails upgrade. Stay tuned for more tips as you embark on your upgrade adventure!

We offer a Pre-Upgrade Questionnaire as a starting point for your Ruby on Rails upgrade. Be sure to answer all of the questions, and keep the worksheet handy to refer to as you go!

Resources

  • nixpkgs-ruby – Bob Vanderlinden’s collection of Nix code for older versions of Ruby can be vitally important for getting old Ruby code running on new operating systems.
  • lock-gemfile – Many legacy Ruby projects don’t have a version number pinned for some or all of their Gems. The lock-gemfile tool helps with that – it will rewrite your Gemfile using the version numbers in your Gemfile.lock. This lets you easily change a few versions at a time instead of having to do all your resolution en masse.
  • mise – Since you’ll likely need to switch back and forth from different versions of Ruby, a version manager is a must; our favorite is mise, but feel free to use asdf, rbenv, rvm or something else.
  • direnv.net – direnv helps manager per-project environment variables using .envrc files; in particular, the “layout ruby” command helps with upgrade projects, as it transparently stores your gems in a per-project .direnv/ruby directory. This can make switching between projects or branches using different versions of ruby much, much easier.
  • ack – ack is a grep-like tool – but it’s optimized for source code. It’s faster than grep, recursive by default, automatically ignores binary files and your .git directory, and has color hilighting by default. Since upgrade projects often involve a tremendous amount of searching, ack is a great tool.