with.rb 4.4 KB
Newer Older
1 2
module ActiveModel
  module Validations
3 4 5 6 7 8 9 10
    module HelperMethods
      private
        def _merge_attributes(attr_names)
          options = attr_names.extract_options!
          options.merge(:attributes => attr_names.flatten)
        end
    end

11 12
    module ClassMethods

13 14
      # Passes the record off to the class or classes specified and allows them
      # to add errors based on more complex conditions.
15
      #
16 17
      #   class Person
      #     include ActiveModel::Validations
18 19 20
      #     validates_with MyValidator
      #   end
      #
21 22
      #   class MyValidator < ActiveModel::Validator
      #     def validate(record)
23 24 25 26 27 28 29 30 31 32 33 34 35
      #       if some_complex_logic
      #         record.errors[:base] << "This record is invalid"
      #       end
      #     end
      #
      #     private
      #       def some_complex_logic
      #         # ...
      #       end
      #   end
      #
      # You may also pass it multiple classes, like so:
      #
36 37
      #   class Person
      #     include ActiveModel::Validations
38 39 40 41
      #     validates_with MyValidator, MyOtherValidator, :on => :create
      #   end
      #
      # Configuration options:
42 43 44 45 46
      # * <tt>on</tt> - Specifies when this validation is active
      #   (<tt>:create</tt> or <tt>:update</tt>
      # * <tt>if</tt> - Specifies a method, proc or string to call to determine
      #   if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
      #   or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
47
      #   The method, proc or string should return or evaluate to a true or false value.
48 49 50 51
      # * <tt>unless</tt> - Specifies a method, proc or string to call to
      #   determine if the validation should not occur
      #   (e.g. <tt>:unless => :skip_validation</tt>, or
      #   <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
52 53
      #   The method, proc or string should return or evaluate to a true or false value.
      #
54 55
      # If you pass any additional configuration options, they will be passed
      # to the class and available as <tt>options</tt>:
56
      #
57 58
      #   class Person
      #     include ActiveModel::Validations
59 60 61
      #     validates_with MyValidator, :my_custom_key => "my custom value"
      #   end
      #
62 63
      #   class MyValidator < ActiveModel::Validator
      #     def validate(record)
64 65 66 67
      #       options[:my_custom_key] # => "my custom value"
      #     end
      #   end
      #
68
      def validates_with(*args, &block)
69
        options = args.extract_options!
70 71 72
        args.each do |klass|
          validator = klass.new(options, &block)
          validator.setup(self) if validator.respond_to?(:setup)
73 74 75 76 77 78 79 80 81

          if validator.respond_to?(:attributes) && !validator.attributes.empty?
            validator.attributes.each do |attribute|
              _validators[attribute.to_sym] << validator
            end
          else
            _validators[nil] << validator
          end

82 83
          validate(validator, options)
        end
84 85
      end
    end
86 87 88 89 90 91 92 93 94 95 96 97 98 99

    # Passes the record off to the class or classes specified and allows them
    # to add errors based on more complex conditions.
    #
    #   class Person
    #     include ActiveModel::Validations
    #
    #     validates :instance_validations
    #
    #     def instance_validations
    #       validates_with MyValidator
    #     end
    #   end
    #
100 101
    # Please consult the class method documentation for more information on
    # creating your own validator.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    #
    # You may also pass it multiple classes, like so:
    #
    #   class Person
    #     include ActiveModel::Validations
    #
    #     validates :instance_validations, :on => :create
    #
    #     def instance_validations
    #       validates_with MyValidator, MyOtherValidator
    #     end
    #   end
    #
    # Standard configuration options (:on, :if and :unless), which are
    # available on the class version of validates_with, should instead be
    # placed on the <tt>validates</tt> method as these are applied and tested
    # in the callback
    #
    # If you pass any additional configuration options, they will be passed
121 122
    # to the class and available as <tt>options</tt>, please refer to the
    # class version of this method for more information
123 124 125 126 127 128 129 130
    #
    def validates_with(*args, &block)
      options = args.extract_options!
      args.each do |klass|
        validator = klass.new(options, &block)
        validator.validate(self)
      end
    end
131
  end
132
end