7 Common Mistakes in Rails Upgrades
Ruby on Rails is a popular web application framework that is constantly evolving with new versions being released frequently. While upgrading to a newer Rails version can bring new features, better performance, and security patches/improvements, it can also be a challenging task.
In this blog post, we will discuss 7 common mistakes made while doing Rails upgrades and how to avoid them.
We have seen customers trying to upgrade Rails from 5.2 to 7.0 and Ruby from 2.5 to 3.1 all under one single pull request and failing to deploy a successful version on production.
The problem with this approach is that it becomes extremely difficult to point out where the problem lies when your user encounters a bug in the app.
Did it happen when you upgraded from Rails 5.2 to 6.0 or in any other jump? Did it happen due to a deprecation warning that was supposed to be handled in Rails 6.0 to 6.1 jump but you skipped that as you tried to upgrade directly from Rails 5.2 to 7.0?
Another problem here is that you miss the chance to achieve small wins by deploying relatively small upgrades to production and thus exposing yourself to greater chances of encountering bugs and downtime to your app.
The only way to avoid these problems is to take a step-wise approach of upgrading only one major or one minor version at a time. If we were to upgrade an app from Rails 5.2 to 7.0, we would first upgrade it to Rails 6.0, deploy to production, then upgrade to 6.1, deploy to production, and then upgrade to 7.0 and deploy to production.
If you also have to upgrade Ruby along with Rails, then the ideal approach is to upgrade them individually. This way you can minimize the risk of bugs creeping in.
Ignoring Deprecation Warnings
We have seen some clients silencing the deprecation warnings instead of addressing them. The reason deprecation warning exists is to alert developers of a behavior of the framework, ruby, or another gem that will not be supported in the future and to give them time to move away from the deprecated behavior which will eventually not be supported.
The problem with silencing the warning is when the deprecated behavior is no longer supported, it will break the application and the developer will have to either roll back the upgrade or make changes to the app really quickly and no developer would like to be in that situation.
Additionally, addressing the deprecation warnings are fairly straightforward most of the time, and the deprecation warning message also indicates how to fix / change the code to get rid of the warning.
It is way easier to address a deprecation warning that is explicit (it tells you the code, the change and the line that’s triggering it) than fixing a bug that you don’t know where it’s happening and what is causing it.
We’ve seen hours of work of debugging to end up finding that the bug was due to something that had a deprecation warning which was never addressed.
When you are upgrading Rails, chances are that you are going to upgrade other gems along with it. But, how do you find out which gems need to be upgraded and to what versions? There are 2 ways to go about this.
bundle update and then it will update every gem to the most
compatible version. The problem with this approach is that since it is going to
update all the possible gems with a compatible higher version, you are
exposing yourself to more bugs which can come due to code / behavior changes
in the upgraded gems.
bundle update rails and then it will break with incompatibility
messages across your gem set and with errors indicating which gems need to be
updated. The downside to this approach is that it takes longer as you have to
manually upgrade gems iteratively until the
bundle update is successful.
The upsides are huge though as chances of bugs creeping comes down as you have only upgraded gems that absolutely needed to be upgraded.
You can read more about it here .
Undocumented Monkey Patches and Forking gems
Yes, Ruby is great because the powers it gives you and one of them is monkey patching existing behavior. This is great because it solves your problems in the short term.
But we have seen enough projects where the monkey patched behavior is left with no comments explaining why it was done in the first place and the developer who did this is no more working at the organization to explain and now you are left with no option but to make sense of the patch work all by yourself which is very close to guess work.
Another big problem we have encountered over the years is forking gems. Lots of times, developers fork open source gems and make changes to it to fit their needs.
But those changes are never submitted to the open source project and the reason for the fork is left to yourself without documenting it. Now it is the team who is working on the upgrade that is left to make sense of why the fork was done, and is it safe to go the released rubygems version of it or make the fork work with the upgraded Rails and other gems.
Lack of test coverage or testing strategy
To ensure that the upgrade of the Rails app is successfully released on production, you need either of the 2 things at least.
First, a good test coverage of your application. Anything above 80% test coverage is considered good if it includes coverage of the critical paths of the applications.
Second, awareness of all the critical paths of the application and ability to test them manually.
If you do not have either of the 2 things in place, it increases the chances of encountering bugs upon releasing it on production. Even with both the strategies in place, you can still set yourself for a buggy release on production and that can be due to not having a dedicated QA team or QA role defined in your workflow.
When the developer doing the code review on the pull request ends up doing the QA of it as well it is not an ideal situation. It can lead to bugs not caught before they are released to your users.
Not using the right tools
There are many ways to go about upgrading your application, but choosing the right tools and the right strategy can go a long way in making your experience smooth.
Something as trivial as branching and code arrangement strategy holds a lot of importance in your workflow. We have seen a lot of teams struggle or end up doing repetitive work because of lack of clearly defined strategy.
To avoid confusion on how to run the upgrades, we contribute and maintain the next_rails gem which:
- Helps us in running 2 different versions of Ruby or Rails in the same branch
- Facilitates running specs for the 2 different versions of Ruby or Rails from the same branch
This goes a long way in debugging issues while doing upgrades without switching branches. It also helps in implementing a gradual deployment strategy with Kubernetes.
We have also seen customers trying to do everything “the Rails way” when it does not make sense for them.
For example, Active Storage is a great gem and very useful for someone allowing users to upload files. But one of our customers wanted to use Active Storage even though their use case did not fit to use it.
What they already had made more sense for them. Using Active Storage would have made their systems more complex. So it is also important to know when to move away from the defaults.
Not Having a Rollback Plan
Finally, not having a rollback plan is a common mistake made while upgrading Ruby or Rails.
Despite careful planning, unexpected issues can arise during the deployment. It is important to have a rollback plan in case of any issues that may arise during the deployment process.
A rollback plan should include steps to revert to the previous version of Rails, restore db backups, and fix issues that caused the rollback.
Upgrading your Ruby or Rails version is essential for keeping your application secure and up to date.
However, upgrading can be a challenging task, especially when you make common mistakes.
In this article, we discussed 7 common mistakes that developers make when upgrading Ruby or Rails and how to avoid them. By avoiding these mistakes, you can make the upgrade process smoother and less stressful.
In conclusion, upgrading Rails can be a daunting task, but with the right approach, you can make it a seamless process.
PS: Need help upgrading Ruby or Rails to their latest stable version? We have some availability to help your team upgrade Ruby/Rails !