Skip to content

Instantly share code, notes, and snippets.

@nevir
Created May 19, 2011 19:19
Show Gist options
  • Save nevir/981496 to your computer and use it in GitHub Desktop.
Save nevir/981496 to your computer and use it in GitHub Desktop.
DataMapper::Property::ValidatedJson
require 'dm-types'
require 'dm-validations'
module DataMapper
module Validations
class DeferredJsonValidator < GenericValidator
def initialize(field_name, pending_error_ivar_name, options={})
super(field_name, options)
@pending_error_ivar_name = pending_error_ivar_name
end
def call(target)
return true unless target.instance_variable_defined?(@pending_error_ivar_name)
message = '%s is not valid JSON: %s' % [
DataMapper::Inflector.humanize(field_name),
target.instance_variable_get(@pending_error_ivar_name),
]
add_error(target, message, field_name)
false
end
end
end
class Property
# Provides a Json-based property that defers JSON validation errors to the validation step of
# the model.
#
# If your JSON fails to validate, the property is represented as nil
class ValidatedJson < Json
attr_reader :pending_error_instance_variable_name
def initialize(*args)
super
@pending_error_instance_variable_name = "#{instance_variable_name}_pending_error".freeze
unless model.skip_auto_validation_for?(self)
# A more manual form of DataMapper::Validations::ClassMethods#add_validator_to_context
validator = Validations::DeferredJsonValidator.new(name, @pending_error_instance_variable_name)
context = model.validators.context(:default)
unless context.include? validator
context << validator
model.send :create_context_instance_methods, :default
end
end
end
def set(resource, value)
begin
super
# Clean up the ivar on success
if resource.instance_variable_defined? pending_error_instance_variable_name
resource.send(:remove_instance_variable, pending_error_instance_variable_name)
end
rescue ::JSON::ParserError => err
resource.instance_variable_set(pending_error_instance_variable_name, err.message)
super(resource, nil)
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment