aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib/active_model/validations/validates.rb
blob: e8935d3794aab9b57e87b5543ecd3cd070a2988a (plain) (blame)
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
module ActiveModel
  module Validations
    module ClassMethods
      # This method is a shortcut to all default validators and any custom
      # validator classes ending in 'Validator'. Note that Rails default
      # validators can be overridden inside specific classes by creating
      # custom validator classes in their place such as PresenceValidator.
      # 
      # Examples of using the default rails validators:
      #   validates :terms, :acceptance => true
      #   validates :password, :confirmation => true
      #   validates :username, :exclusion => { :in => %w(admin superuser) }
      #   validates :email, :format => { :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create }
      #   validates :age, :inclusion => { :in => 0..9 }
      #   validates :first_name, :length => { :maximum => 30 }
      #   validates :age, :numericality => true
      #   validates :username, :presence => true
      #   validates :username, :uniqueness => true
      # 
      # The power of the +validates+ method comes when using cusom validators
      # and default validators in one call for a given attribute e.g.
      #   class EmailValidator < ActiveModel::EachValidator
      #     def validate_each(record, attribute, value)
      #       record.errors[attribute] << (options[:message] || "is not an email") unless
      #         value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
      #     end
      #   end
      # 
      #   class Person
      #     include ActiveModel::Validations
      #     attr_accessor :name, :email
      # 
      #     validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 100 }
      #     validates :email, :presence => true, :email => true
      #   end
      # 
      # Validator classes my also exist within the class being validated
      # allowing custom modules of validators to be included as needed e.g.
      # 
      #   module MyValidators
      #     class TitleValidator < ActiveModel::EachValidator
      #       def validate_each(record, attribute, value)
      #         record.errors[attribute] << "must start with 'the'" unless =~ /^the/i
      #       end
      #     end
      #   end
      # 
      #   class Film
      #     include ActiveModel::Validations
      #     include MyValidators
      # 
      #     validates :name, :title => true
      #   end 
      # 
      def validates(*attributes)
        validations = attributes.extract_options!

        raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
        raise ArgumentError, "Attribute names must be symbols" if attributes.any?{ |attribute| !attribute.is_a?(Symbol) }
        raise ArgumentError, "You need to supply at least one validation" if validations.empty?
        
        validations.each do |key, options|
          begin
            validator = const_get("#{key.to_s.camelize}Validator")
          rescue NameError
            raise ArgumentError, "Unknown validator: '#{key}'"
          end

          validates_with(validator, (options == true ? {} : options).merge(:attributes => attributes))
        end
      end
    end
  end
end