1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
module Validatable
def self.included(klass) #:nodoc:
klass.extend Validatable::ClassMethods
klass.extend Validatable::Macros
end
# call-seq: valid?
#
# Returns true if no errors were added otherwise false. Only executes validations that have no :groups option specified
def valid?
valid_for_group?(nil)
end
# call-seq: errors
#
# Returns the Errors object that holds all information about attribute error messages.
def errors
@errors ||= Validatable::Errors.new
end
def valid_for_group?(group) #:nodoc:
run_before_validations
errors.clear
self.class.validate_children(self, group)
self.validate(group)
errors.empty?
end
def times_validated(key) #:nodoc:
times_validated_hash[key] || 0
end
def increment_times_validated_for(validation) #:nodoc:
if validation.key != nil
if times_validated_hash[validation.key].nil?
times_validated_hash[validation.key] = 1
else
times_validated_hash[validation.key] += 1
end
end
end
# call-seq: validate_only(key)
#
# Only executes a specified validation. The argument should follow a pattern based on the key of the validation.
# Examples:
# * validates_presence_of :name can be run with obj.validate_only("presence_of/name")
# * validates_presence_of :birthday, :key => "a key" can be run with obj.validate_only("presence_of/a key")
def validate_only(key)
validation_name, attribute_name = key.split("/")
validation_name = validation_name.split("_").collect{|word| word.capitalize}.join
validation_key = "#{self.class.name}/Validatable::Validates#{validation_name}/#{attribute_name}"
validation = self.class.all_validations.find { |validation| validation.key == validation_key }
raise ArgumentError.new("validation with key #{validation_key} could not be found") if validation.nil?
errors.clear
run_validation(validation)
end
protected
def times_validated_hash #:nodoc:
@times_validated_hash ||= {}
end
def validate(group) #:nodoc:
validation_levels.each do |level|
validations_for_level_and_group(level, group).each do |validation|
run_validation(validation) if validation.should_validate?(self)
end
return unless self.errors.empty?
end
end
def run_validation(validation) #:nodoc:
validation_result = validation.valid?(self)
add_error(validation.attribute, validation.message(self)) unless validation_result
increment_times_validated_for(validation)
validation.run_after_validate(validation_result, self, validation.attribute)
end
def run_before_validations #:nodoc:
self.class.all_before_validations.each do |block|
instance_eval &block
end
end
def add_error(attribute, message) #:nodoc:
self.class.add_error(self, attribute, message)
end
def validations_for_level_and_group(level, group) #:nodoc:
validations_for_level = self.all_validations.select { |validation| validation.level == level }
return validations_for_level.select { |validation| validation.groups.empty? } if group.nil?
validations_for_level.select { |validation| validation.groups.include?(group) }
end
def all_validations #:nodoc:
res = self.class.validations_to_include.inject(self.class.all_validations) do |result, included_validation_class|
result += self.send(included_validation_class.attribute).all_validations
result
end
end
def validation_levels #:nodoc:
self.class.all_validations.inject([1]) { |result, validation| result << validation.level }.uniq.sort
end
end
|