Upgrading Rails from 4.2 to 5.2, 6.0 - collected notes
Tags: rails
Published: 2020-01-14 08:44:16

---
title: Upgrading Rails from 4.2 to 5.2, 6.0 - collected notes
published: true
date: 2020-01-14 08:00:00 UTC
tags: [rails]
canonical_url: http://www.stefanwienert.de/blog/2019/06/04/upgrading-to-rails-5-2-notes/
---

Recently, I've upgraded a bunch of apps to Rails 5.2 and 6.0, I want to share some common issues and the process I follow:

## General upgrade process

1. Have a quick overview of the Rails upgrade guide, to get a feeling what kind of things changed between versions:
  - https://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html
1. I change the Rails requirement in Gemfile to the next minor version, like `gem "rails", "~> 5.0.0"`, Maybe also bump the Ruby version to the required one, if your current one is too old. But I try to usually do it separately, because newer Ruby versions can also break your app.
2. Now comes the `bundle update rails`, This will probably fail because some other Gems collide. If those Gems have version constraints in your Gemfile, relax that. Try adding more and more Gems to `bundle update rails rack sass-rails` etc., Use a `bundle update` without Gems only as last resort, as this will update ALL Gems at once and usually break a lot of things. 
In my experience, common Gems that have to be upgraded together with Rails,  are:
  - paginators (will_paginate)
  - form gems (simple-form)
  - ActiveRecord Gems (paper_trail, acts-as-taggable-on)
  - Admin-interfaces (Active Admin)
  - Asset-Pipeline Gems (sass, sass-rails, font-awesome-rails)
  - bootsnap, rspec-rails

3. Try to boot app, like `bundle exec rails c`, Fix any errors that happen, then
4. Run `rails app:update`. The will launch a command line wizard, that will interactively compare all the config files of your app to that of a newly generated Rails app. My tip: Try to adjust your files in a editor to match the Rails standard as closest as possible. E.g. our `config/environments/development.rb` looks almost the same like the generated. All custom config by us is then on the bottom of the file and can be easily moved between upgrades later. Alternatively, use [Rails-Diff](http://railsdiff.org/5.2.4/6.0.2.1) to compare config changes between versions.
5. Try to run tests, fix deprecations
6. Run development server and click around
7. Push to CI. Hint: Try to make deprecations more visible, make them an error, and eager load on test (to remove bugs that happen by invalid files that the development system didn't catch): 

```ruby
# config/environments/test.rb

    config.eager_load = ENV['CI'].present?
    config.active_support.deprecation = ENV['CI'].present? ? :raise : :stderr
    # Show the full stacktrace of deprecations, 
    #   e.g. middleware. Maybe put that line in application.rb after loading rails
    ActiveSupport::Deprecation.debug = true
  end
```

## Rails 5.0

### Protected Attributes is gone!

If you previously have used `attr_accessible` and similar, that stuff is gone!

Finding possible occurences:

```bash
ag new.\*params app | grep -v permit
ag update.\*params app | grep -v permit
```

Sometimes, e.g. for query models on a get request, this kind of pattern is useful:

```ruby
# passing whole params
MyForm(params.permit!.to_h)

# passing only params, that might not be there on the first page load
MyForm(params[:my_form]&.permit!&.to_h)
```

### Important: Belongs\_to required by default!

This will probably brake old apps. To reduce friction for future upgrades, adjust `config/application.rb`:

```ruby
module MyApp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.0
    ...

    config.active_record.belongs_to_required_by_default = false
  end
end
```

Some later Rails generator brings this line into a config/initializers, but that seems to be having no effect, only adding to application.rb.

### before\_filter -\> before\_action

(Same with after\_action)

```bash
sed -i 's/before_filter/before_action/g' `find app -type f`
sed -i 's/after_filter/after_action/g' `find app -type f`
```

### Controller tests/specs - get/post must be keyword arguments

In case you are using RSpec, just use this awesome Gems to convert everything:

```bash
gem install rails5-spec-converter
rails5-spec-converter
```

This converts 95% of the scenarios, only very custom session/cookies stuff must be checked manually.

### redirect\_to :back deprecated

```diff
- redirect_to :back, alert: "whatever"
+ redirect_back fallback_location: '/', alert: "whatever"
```

## Rails 5.1

- image\_tag does not allow nil! `nil is not a valid asset source`, wrap all image\_tag in an `if my_model.attachment.present?`
- database\_cleaner is not required for browser tests anymore (Rspec: System Tests)
- add 'listen' gem to development/test group `gem "listen"`

### response.success? -\> response.sucessful?

```bash
sed -i 's/be_success$/be_successful/g' `ag be_success$ spec -l`
```

### Foreign Key mismatch

```
ActiveRecord::MismatchedForeignKey: Column `cooperation_id` on table `cooperation_data_points` does not match column `id` on `cooperations`, which has type `bigint(20)`. To resolve this issue, change the type of
the `cooperation_id` column on `cooperation_data_points` to be :bigint. (For example `t.bigint :cooperation_id`).
Original message: Mysql2::Error: Cannot add foreign key constraint: ALTER TABLE `cooperation_data_points` ADD CONSTRAINT `fk_rails_3979ee89c8`
FOREIGN KEY (`cooperation_id`)
  REFERENCES `cooperations` (`id`
```

- Problem: db/schema.rb does not specify correct primary key types (integer vs. bigint)
- Solution: Run `rails db:schema:dump`

## Rails 5.2

### Arel.sql

All `order` and `pluck` columns should be checked and any non-trivial statement must be wrapped in Arel.sql:

```
- .order('length(name) asc').first
+ .order(Arel.sql('length(name) asc')).first
```

Find occurences of order/pluck with a string, check if there is function call or even an SQL injection possibility :) (like `order(params[:sort])`)

- `ag "order\('"`
- `ag 'order\("'`
- `ag "pluck\('"`
- `ag 'pluck\("'`

## Rails 6.0

One very obvious error was the introduction of host checking (against DNS rebinding attacks). We don't need that, as all our apps are proxied in production. In addition, we have dynamic hostnames in development for every developer, so we disable that:

```
# config/application.rb
config.hosts.clear
```

Other things we noticed:

- `scope` - cannot contain the class name itself, just plain calls to where/order etc. (no `scope :active { User.where(active: true) }`)
- `update_attributes` -\> `update` simple sed
- Tests/specs: `content_type` -\> `media_type`
- Gems:
  - in one project, that update line succeeded first: `bundle update rails draper devise sass-rails font-awesome-rails annotate premailer-rails`
  - other gems that produced errors while booting: `bundle update coffee-rails slim-rails bullet pry-rails pry-rescue bootsnap airbrake rspec-rails`
  - `gem 'rspec-rails', '~> 4.0.0.beta2'`
  - `gem "cancancan", "~> 3.0"`
  - will-paginate must be upgraded
- If you are needing helpers in non-controller/view files, there was an older snippet on Stackoverflow, to use `ActionView::Base.new`, replace with: `ActionView::Base.new(ActionView::LookupContext.new('.'), {})`

## Ruby 2.4+

Meanwhile, if you also upgrading Ruby, one error we ran into:

### webmock \> 2, vcr \> 3

```
undefined method `<3, :continue_timeout=>nil, :debug_output=>nil}:Hash
```

If you had running VCR version less than 3 and used HTTP Basic auth, you need to convert your cassettes: [https://gist.github.com/glaszig/9170b1cf2186674faeead74a68606c5d](https://gist.github.com/glaszig/9170b1cf2186674faeead74a68606c5d)

### Deprecations Fixnum/Bignum -\> Integer

- Substitute your own usages of "Fixnum" with Integer.
- Upgrade all Gems with the error

* * * 

So far, I will update that post if I find more common stuff.