app/validators/array_validator.rb
# This custom validator allows you to validate each element in an Array field.
# Source: https://gist.github.com/ssimeonov/6519423
# See app/models/location.rb for usage. Here's an example:
# validates :admin_emails, array: {
# format: { with: /some regex/,
# message: "Please enter a valid email" } }
class ArrayValidator < ActiveModel::EachValidator
def initialize(options)
super
@validators = options.except(:class).map do |(key, args)|
create_validator(key, args)
end
end
def validate_each(record, attribute, values)
helper = Helper.new(@validators, record, attribute)
Array.wrap(values).each do |value|
helper.validate(value)
end
end
private
class Helper
def initialize(validators, record, attribute)
@validators = validators
@record = record
@attribute = attribute
end
def validate(value)
@validators.each do |validator|
next if value.nil? && validator.options[:allow_nil]
next if value.blank? && validator.options[:allow_blank]
run_validator(validator, value)
end
end
def run_validator(validator, value)
validator.validate_each(@record, @attribute, value)
rescue NotImplementedError
validator.validate(@record)
end
end
def create_validator(key, args)
opts = { attributes: attributes }
opts.merge!(args) if args.is_a?(Hash)
validator_class(key).new(opts).tap(&:check_validity!)
end
def validator_class(key)
validator_class_name = "#{key.to_s.camelize}Validator"
validator_class_name.constantize
rescue NameError
"ActiveModel::Validations::#{validator_class_name}".constantize
end
end