require 'json_with_indifferent_access' module JSONSerializedField extend ActiveSupport::Concern module ClassMethods def json_serialize(*fields) fields.each do |field| class_eval <<-CODE serialize :#{field}, JSONWithIndifferentAccess validate :#{field}_has_no_errors def #{field}=(input) @#{field}_assignment_error = false case input when String if input.strip.length == 0 self[:#{field}] = ActiveSupport::HashWithIndifferentAccess.new else json = JSON.parse(input) rescue nil if json self[:#{field}] = ActiveSupport::HashWithIndifferentAccess.new(json) else @#{field}_assignment_error = "was assigned invalid JSON" end end when Hash self[:#{field}] = ActiveSupport::HashWithIndifferentAccess.new(input) else @#{field}_assignment_error = "cannot be set to an instance of \#{input.class}" end end def #{field}_has_no_errors errors.add(:#{field}, @#{field}_assignment_error) if @#{field}_assignment_error end CODE end end end end