serializeを使うと柔軟にデータを保存できるようになって便利だが、バリデーションを書きづらいという問題がある。こういう場合は ActiveModel::Validations#read_attribute_for_validation を使うとRailsのバリデーション機構を使いまわすことができる。
例えば File モデルに data 属性があってそれがserializeされていて、 data には "name" "link" というキーがあり、 "name" は必須かつ長さ255以下、 "link" は必須にしたいとする。そういう場合はこんな感じで書ける
app/models/file.rb
class File < ActiveRecord::Base
DATA_KEYS = %i(name link).freeze
serialize :data, Hash
validates :name, presence: true, length: { maximum: 255 }
validates :link, presence: true
def read_attribute_for_validation(key)
DATA_KEYS.include?(key) ? data[key] : super
end
end