In contrast to languages such as Java, the Ruby on Rails ecosystem has little tradition of keeping APIs backward compatible. Hence, new versions of Rails and Ruby gems often break existing code, making an upgrade very time intensive.
Not upgrading is not an option either. Once you get too far behind the latest version of Rails you will not receive any further security updates. Given the severity of some of the vulnerabilities that have been disclosed in the past, you probably do not want to expose an unpatched Rails application to the open Internet.
There are products like our own Rails LTS that offer security patches for old versions of Rails. However, if you want to take advantage of the latest features, you will find yourself locked in an eternal rat race of upgrading your application dependencies every few months.
This chapter wants to give some advice for dealing with this sitation.
Gems increase the cost of upgrades
When adding a new gem dependency, consider the cost of upgrading that gem through the lifespan of your application. Will the gem's author still be interested in maintaining the library two years down the road? When push comes to shove, would you be willing to replace that gem or take over maintenance if there is no version compatible with a new version of Rails?
Be aware of different upgrade costs between libraries that provide low-level abstractions and those that offer highly coupled mini frameworks. For instance a library that supplies geographical calculations might not even have a dependency on Rails and is unlikely to ever break during an upgrade. Whereas a gem that dynamically generates an admin backend for your application will almost certainly break after a new Rails release due to its many hooks into the internals of Rails.
Upgrades are when you pay for monkey patches
Monkey patches (or "freedom patches") describe the practice of opening up an existing class from a gem dependency and overriding some method with custom behavior. While this can be a way to quickly move on when encountering a fatal library bug, monkey patches are usually the first thing that break when upgrading Rails.
Be careful when monkey patching the internals of a class that does not belong to you. You will pay for it later.
If you find a bug in a gem that you like, consider forking the gem, committing your fix with a test and creating a pull request to the original author. This way your monkey patch can soon be replaced with the next official version of the gem. It also makes for good karma.
Don't live on the bleeding edge
There is no need to upgrade to a new version of Rails on the day it becomes available. Wait until a major Rails release has matured into a couple of patch levels before upgrading, i.e. don't upgrade to Rails 6.0.0 right away, but wait until Rails 6.0.3 is published.
This also gives authors of your other gem dependencies a chance to update their library to integrate with the new version of Rails.