[Tech] Upgrading Givey to Rails 5

by Carl Markham

25 November 2016

I have mentioned in a previous blog post that we use Ruby on Rails as the back end framework
for Givey. We were using Rails 4.x up until a couple of months ago when I decided it was time
for an upgrade. I knew upgrading to a new major version of Rails wouldn’t go as smoothly as
I would like, so today, I will outline the challenges that came with this upgrade and how we
overcame them.

The first step was to simply set Rails to use version 5.0.0.1 in our gem file and run bundle update.
I knew this wasn’t going to work, but it would give me an idea as to how much wasn’t going to work.
As expected, my terminal was lit up with the color red.

The issue was because a lot of the gems we use needed to be upgraded. So, I updated those gems and tried
again.

So, our gems are all updated and we are using Rails 5. Time to run our development server. And……crash.
This was expected. A lot has changed from Rails 4 to 5. With the changelog open, I scoured over the code and
updated the offending lines. Lets take a closer look at some of those lines.

Most of our code would work fine in the new Rails 5 env. There was a lot of deprecation warnings but these
wouldn’t prevent the app from running. Most of the issues came from a few config files and initializers which
needed to be updated.

For example: We use ActiveJob to queue up our jobs. With the update, ActiveJob
is now used as an instance with a constructor. A simple change.

While the deprecations weren’t needing to be fixed right now, I felt it was best to sort them out
while I was in the process of changing a lot of things anyway.
Most of our classes extend some form of Base, whether it be ActiveRecord::Base, ActiveJob::Base etc.
So, this was just a case of updating these extensions. A simple find and replace in the IDE was able to fix
these easily.

One of the big issues was parameters. Up until Rails 5, parameters inherited from Hash. With Rails 5,
parameters now inherited from ActionController::Parameters. For the most part, this was fine in our app code.
The issue came down to our tests. We use the params a lot in the tests when we are referring to a Hash:

expect(model).to receive(:update).with({foo: 'bar'})

The problem is, this code is expecting the update method of the model to receive a Hash, when in fact it is
receiving an instance of ActionController::Parameters.
I looked for a way around this but I couldn’t find anything. So, I decided to create a method in the test helpers
which would convert this Hash to an instance of ActionController::Parameters. the following is that helper:

module ParamHelper
  def to_params hash
    ActionController::Parameters.new hash
  end
end

Quite a simple method which could have been placed inline like so

expect(model).to receive(:update).with(ActionController::Parameters.new({foo: 'bar'}))

but for the sake of readability and line length I decided to abstract it.

There were a few more nuances such as redirect :back being changed to redirect_back and needing to use render plain
rather than render text, but these were simple changes.

Another big thing was autoloading. Rails 5 disables it by default in production apps. So, I had to track down
all module calls from within our code to see if the module needed to be included or not.

After those changes, it was just a matter of running the tests and peer testing to make sure everything was alright.

Leave a Reply

Your email address will not be published. Required fields are marked *