Second Copy 2 Created with Sketch.

Gem shards

A Ruby & Crystal blog

Rails 5.1 upgrade - TypeError: can’t quote Hash

When upgrading our Rails app to 5.1 we received the following error when trying to access some pages:

TypeError: can’t quote Hash
ruby-2.4.1/gems/activerecord-5.1/lib/active_record/connection_adapters/abstract/quoting.rb:196:in `_quote'

Together with Sidney (sidofc) we decided to dive into the issue.

Identifying the issue

When looking at the stack trace, it is clear the problem starts in a Rails association. After tweaking the association and trying to replicate it in a new Rails app we kept getting the same error.

Before we wanted to submit a issue to the Rails repository we decided to to take a look at our database columns. We decided to remove each column and try to replicate the error.

We’re using a Django inherited MySQL database in our application. Rails has ‘reserved words’ which you can’t use in your application for method names for example. This is also the case for table columns. Our database had columns such as public, class and private. So we thought the issue could come from columns with these words. Sidney wrote a migration script to remove each column and check if the problem persisted. Here’s an example of our script:

class RemoveColumns < ActiveRecord::Migration[5.1]
  def change
    working = false
    columns = Answer.columns.map &:name
    rm_cols = columns - %w[cols to keep]
    rm_target = ''
    until working || rm_cols.empty?
      working = true
      begin
        puts "attempting to run query with #{rm_cols.first} column present"
        Question.last.reload.replies.reload.count
      rescue => e
        rm_target = rm_cols.shift.to_s.downcase.to_sym
        puts "had to rescue #{rm_target} column #{e}"
        remove_column :answer, rm_target
        working = false
      end
    end
    puts "works after removing #{rm_target}" if working
    # Stop the migration from passing, as we
    # need to rerun this script multiple times
    exit 1
  end
end

We discovered the problem occurred when using a attribute with the same name as the table. Such as table with the name ‘question’ which has a column named ‘question’. Rails 5.1 stopped handling this use case. Why? We’re not sure, the commit history and changelog won’t say. But it’s never a good idea to have column with the same name as the table. Even if it’s only to prevent confusion.

The solution

So we added migrations to rename the database columns to something else than the table name. We identified all tables with this issue by executing the following MySQL query:

SELECT * FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'table_name'
AND TABLE_NAME = COLUMN_NAME;

Also the attributes of the model needed to change in the application to match the new column names. Lucky for us, it only occurred in two tables. Within a few minutes we managed to make our application Rails 5.1 ready.