For the past few months at Kiprosh, we've done versions upgrade of multiple mid to large scale Ruby on Rails applications. One of them was running Rails version 3.2.22. That's where we found out that, we need to make a lot of changes in our codebase to run our application on version 4.0. Hence, we thought to write this blog post to share our insights and recommended strategies for upgrading such mid to large Rails applications.
Rails guides provide us a brief information on how to upgrade the Rails app, but we need to know more to smooth our development process.
To make our workflow smoother and less painful, we will explore some insights in this article. I hope these insights will help in smoothening the upgrading experience.
During our upgrade process we will use bundle install and bundle update many times. When we run bundle install or bundle update we may get gems dependency error(s).
If we have a Gemfile like one on the right side (fig 1) then we can empty Gemfile.lock and bundle install gems, doing so bundler will resolve such dependencies.
Hence, we can run the following commands whenever needed or whenever it is overwhelming to resolve such dependency error(s).
Note: check gemspec of each gem to find out which gem makes the dependency error(s)/issue(s).
As our application grows in terms of features and codebase, Rails commands will become slower (may take 15-25 sec for larger apps) and development will become slow & boring.
Here we will see how zeus helps us to speed up commands.
As compared to other gems, zeus is designed to work outside bundler (no need to add in Gemfile) and compatible with parallel_tests where spring lacks native support for gem parallel_tests.
we recommend to stay on zeus for Rails version 3 & 4. Zeus does not support Rails 5 yet as hot reload mechanism changed in Rails 5.
spring gem developed in pure ruby and that's the only reason it was added Rails 4.1 stack as a default gem under development group. It will take time when we run command for the first time in the console then a background process will start for spring server.
aravind .. spring app | microposts | started 4 mins ago | developm..
Since, spring doesn't natively support multi-thread, it won't be a best match for gem parallel_tests. For more info you can check this issue.
Note: zeus works faster as compared to spring.
Once we reach Rails version 5.0, we can use bootsnap instead of zeus, as zeus does not support Rails 5.1 yet.
We recommend to use bootsnap, once we are on Rails version 5 or later.
After following above steps, we are good to go for upgrading Rails.
As we are working on Rails upgrade, we have upgraded a Rails app which is running on a Rails version 3.x. Here, we want to share the breaking changes in versions 3 and 4 which makes the upgrading process painful and hectic.
The initial breaking change we encountered with Rails 4 was routes. In Rails 4 match has been removed and we have to use one of get , put, post and delete methods for HTTP GET, PATCH, POST and DELETE respectively.
Replacing match with the respective http method is time consuming if the routes are not well documented.
We can find complete list of changes in upgrade Ruby on Rails guides and the following gems will help us with smooth transition from version 3 to 4.
The protected_attributes gem provides attr_accessible , attr_protected methods in Rails 4, then we can replace these methods with strong parameters.
The rails-observers gem removed from stack in Rails 4. We can add this gem to Gemfile, If observer exist in our app.
The gem actionpack-page_caching provides caches_page, page_cache_directory methods in our Rails app. We can use this gem if these methods are used in our rails app.
The gem actionpack-action_caching provides caches_page , caches_action and before_action filter for caches_action . We can use this gem if our Rails app uses these methods.
Let's continue with the problems we have faced while upgrading Rails from version 3.x to 4.x.
If we have older jquery-rails of version 2.3.0 in our app and other gems(ex: active_admin) may require jquery-rails of version 3.0 or later, then to upgrade all other gems, assets gems shouldn't create a problem as we don't want to upgrade jquery.
Note: Rails 5.1 dropped jquery from default stack. Find more info here.
To avoid upgrading jquery or jquery-rails gem what we can do is we can extract the assets from jquery-rails gem and include it in our application.js or wherever it needs. Lets see how we did it.
Similarly, we can remove other assets gems if they have a dependency problem with other gems.
The upgrading Ruby on Rails at rails.org will give us a full brief about how we can proceed with the upgrade and what are the major changes/features in rails 3, 4 or 5.
But, here we have a different approach in upgrading Rails viz., instead of upgrading all the gems at once, we can upgrade one gem at a time which covers a specific module(ex: jobs, mailers, ..) of our application.
But, sometimes a gem needs another gem to be updated along with it due to dependency, in that case, we need to upgrade both.
Upgrade all your gems one by one in older Rails version. Then upgrade Rails, if it needs the Ruby upgrade then do both at the same time. Repeat this until you reach the latest Rails version.
For example, If we are on Rails 3.2.22, then we upgrade all the gems one by one where gems support Rails 3.2.22 & 4.0 and then we will proceed with upgrade rails to version 4.0. But, Rails 4.0 requires ruby 1.9.3 and above. If our app is running on older ruby version (< 1.9.3) then we need to upgrade ruby then rails or both.
If we follow the above approach and upgrade gem one at a time and push it to the production, then we may get fewer errors and end up as happy developer. If there are any bugs in production then it will be easy to handle.
Let us know what you are up to on Rails upgrade and do drop us a comment if you have any queries, thoughts or suggestions.
Developing Slack Bot in Elixir Phoenix.