Daniel Becker
Daniel Becker

Reputation: 821

Activerecord store only returns empty hash after rails 5 upgrade

I am in the process of upgrading a rails 4.2 application to rails 5. One of the models uses an ActiveRecord::Store. When retrieving records after the upgrade, said store only returns an empty Hash. I have no idea why that's happening and wasn't able to find anything in the changelog. So any help and explanation would be appreciated.

Here's the output of the rails 4 console:

=> #<StoredDataQuery ..., config: {"start_date"=>6, "end_date"=>0, ...>

and rails 5:

=> #<StoredDataQuery ..., config: {}, ...

psql output:

development=# SELECT config FROM stored_data_queries WHERE id=1;
                   config
---------------------------------------------
 --- !ruby/hash:ActionController::Parameters+
 start_date: 6                              +
 end_date: 0                                +
 interval: day                              +

(1 row)

Looking at the SQL output, I'm suspecting it has something to do with the data being serialized as ActionController::Parameters.

Thanks for your help!

Upvotes: 2

Views: 474

Answers (2)

Daniel Becker
Daniel Becker

Reputation: 821

Here's how to fix it in sql (postgres):

UPDATE stored_data_queries SET config = replace(config, 'ActionController::Parameters', 'ActiveSupport::HashWithIndifferentAccess');

Upvotes: 3

M. Edennhofer
M. Edennhofer

Reputation: 81

Same here, after Upgrading Zammad from Rails 4.2 to Rails 5.0. After some research I found out that active record is only reading ActiveSupport::HashWithIndifferentAccess from store anymore (other classes are skipped).

So for migration you can overwrite ActiveRecord::Store::IndifferentCoder.as_indifferent_hash in a migration, read all related records from database and just save them back (then all ActionController::Parameters are converted to ActiveSupport::HashWithIndifferentAccess).

For me the following migration (under Rails 5.0) has worked to convert all ActionController::Parameters to ActiveSupport::HashWithIndifferentAccess:

require 'active_record/store'
module ActiveRecord
  module Store
    class IndifferentCoder
      def self.as_indifferent_hash(obj)
        case obj
        # re-enable using ActionController::Parameters in stores,
        # convert them to ActiveSupport::HashWithIndifferentAccess
        # at reading from db
        when ActionController::Parameters
          obj.permit!.to_h
        # /re-enable
        when ActiveSupport::HashWithIndifferentAccess
          obj
        when Hash
          obj.with_indifferent_access
        else
          ActiveSupport::HashWithIndifferentAccess.new
        end
      end
    end
  end
end

class FixedStoreUpgrade45 < ActiveRecord::Migration[5.0]
  def up
    [Macro, Taskbar, Calendar, Trigger, Channel, Job, PostmasterFilter, Report::Profile, Setting, Sla, Template].each do |class_name|
      class_name.all.each do |record|
        begin
          record.save!
        rescue => e
          Rails.logger.error "Unable to save/update #{class_name}.find(#{record.id}): #{e.message}"
        end
      end
    end
  end
end

Upvotes: 2

Related Questions