Railsのエラー『ActiveRecord::SerializationTypeMismatch』の解決方法

Railsのエラー『ActiveRecord::SerializationTypeMismatch』の解決方法

このエラーは、ActiveRecordがカラムのデータ型と保存されているデータの型が一致しないときに発生する。特に、JSONや配列の型を扱う際に発生しやすい。この記事では、エラーの原因と対処法を説明する。

エラーの発生条件

以下のようなケースでこのエラーが発生する。

  • カラムの型としてjsonまたはjsonbを指定しているが、保存するデータが不適切
  • シリアライズされたデータの型がカラムの型と異なる
  • 古いデータが不適切な型で保存されている

エラーメッセージの例

このエラーは、例えば以下のようなメッセージで表示される。

ActiveRecord::SerializationTypeMismatch: can't load `Object`: was supposed to be a Hash, but was a String

原因の確認

カラムの型を確認するには、Railsコンソールで次のコマンドを実行する。

ActiveRecord::Base.connection.columns(:users).find { |c| c.name == "settings" }.sql_type


例えば、設定値がjsonb型であるべきなのにstringとして保存されている場合、エラーが発生する可能性がある。

データの型を統一する

正しい型でデータを保存するように修正する。

user.settings = JSON.parse(user.settings) if user.settings.is_a?(String)
user.save!

マイグレーションでカラムの型を変更する

データ型が適切でない場合、マイグレーションを作成して型を変更する。

class ChangeSettingsToJson < ActiveRecord::Migration[6.0]
  def change
    change_column :users, :settings, :jsonb, using: 'settings::jsonb'
  end
end

シリアライズを明示的に指定する

モデルにserializeを指定すると、データを適切に扱えるようになる。

class User < ApplicationRecord
  serialize :settings, JSON
end

古いデータを修正する

既存データの型が適切でない場合、データベースの値を修正する。

User.find_each do |user|
  user.update(settings: JSON.parse(user.settings)) if user.settings.is_a?(String)
end

まとめ

  • カラムの型とデータの型を一致させる
  • データを適切に変換して保存する
  • マイグレーションでカラムの型を変更する
  • モデルにserializeを指定する
  • 古いデータを修正する