Home > Net >  Rails update need to revert to storing json strings as hash
Rails update need to revert to storing json strings as hash

Time:06-25

We are updating to a newer version of Rails and in previous versions saving object.to_json to a jsonb column would automatically convert it to a hash. Because of this, we expect to retrieve data from those fields as a hash.

We have no need to use the functionality of storing strings in our jsonb fields, so instead of digging through tens of thousands of lines of code to find every possible offender, I was trying to find where I could revert the behavior back to automatically saving them as hashes.

Where does it format the data it's about to save to a postgres db?

CodePudding user response:

My professional opinion would be to go through the project and fix everything, because if you try to fix the framework, any update will break and potentially undo any of the "fixes" you can try to do to make it behave like an old version of rails.

That said, if you REALLY want to dive into the nuts and bolts of rails, you can look at the following classes and override/monkeypatch them:

jsonb mappping seems to be handled by this file: https://github.com/rails/rails/blob/f95c0b7e96eb36bc3efc0c5beffbb9e84ea664e4/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb

module ActiveRecord
  module ConnectionAdapters
    module PostgreSQL
      module OID # :nodoc:
        class Jsonb < Type::Json # :nodoc:
          def type
            :jsonb
          end
        end
      end
    end
  end
end

which inherits from Type::Json.

https://github.com/rails/rails/blob/f95c0b7e96eb36bc3efc0c5beffbb9e84ea664e4/activerecord/lib/active_record/type/json.rb

module ActiveRecord
  module Type
    class Json < ActiveModel::Type::Value
      include ActiveModel::Type::Helpers::Mutable

      def type
        :json
      end

      def deserialize(value)
        return value unless value.is_a?(::String)
        ActiveSupport::JSON.decode(value) rescue nil
      end

      def serialize(value)
        ActiveSupport::JSON.encode(value) unless value.nil?
      end

      def changed_in_place?(raw_old_value, new_value)
        deserialize(raw_old_value) != new_value
      end

      def accessor
        ActiveRecord::Store::StringKeyedHashAccessor
      end
    end
  end
end

It seems like if you mess with the serializer and the deserializer function, you probably could achieve what you want... but again, I totally do not recommend this! You will make your codebase subject to break with any upgrade of rails. The automatic json encode and decode is probably what is messing you up.

  • Related