with.rb 4.4 KB
Newer Older
1
module ActiveModel
2 3

  # == Active Model validates_with method
4
  module Validations
5 6 7 8 9 10 11 12
    module HelperMethods
      private
        def _merge_attributes(attr_names)
          options = attr_names.extract_options!
          options.merge(:attributes => attr_names.flatten)
        end
    end

13 14
    module ClassMethods

15 16
      # Passes the record off to the class or classes specified and allows them
      # to add errors based on more complex conditions.
17
      #
18 19
      #   class Person
      #     include ActiveModel::Validations
20 21 22
      #     validates_with MyValidator
      #   end
      #
23 24
      #   class MyValidator < ActiveModel::Validator
      #     def validate(record)
25 26 27 28 29 30 31 32 33 34 35 36 37
      #       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:
      #
38 39
      #   class Person
      #     include ActiveModel::Validations
40 41 42 43
      #     validates_with MyValidator, MyOtherValidator, :on => :create
      #   end
      #
      # Configuration options:
44 45 46 47 48
      # * <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>).
49
      #   The method, proc or string should return or evaluate to a true or false value.
50 51 52 53
      # * <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>).
54 55
      #   The method, proc or string should return or evaluate to a true or false value.
      #
56 57
      # If you pass any additional configuration options, they will be passed
      # to the class and available as <tt>options</tt>:
58
      #
59 60
      #   class Person
      #     include ActiveModel::Validations
61 62 63
      #     validates_with MyValidator, :my_custom_key => "my custom value"
      #   end
      #
64 65
      #   class MyValidator < ActiveModel::Validator
      #     def validate(record)
66 67 68 69
      #       options[:my_custom_key] # => "my custom value"
      #     end
      #   end
      #
70
      def validates_with(*args, &block)
71
        options = args.extract_options!
72 73 74
        args.each do |klass|
          validator = klass.new(options, &block)
          validator.setup(self) if validator.respond_to?(:setup)
75 76 77 78 79 80 81 82 83

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

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

    # 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
    #
102 103
    # Please consult the class method documentation for more information on
    # creating your own validator.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
    #
    # 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
123 124
    # to the class and available as <tt>options</tt>, please refer to the
    # class version of this method for more information
125 126 127 128 129 130 131 132
    #
    def validates_with(*args, &block)
      options = args.extract_options!
      args.each do |klass|
        validator = klass.new(options, &block)
        validator.validate(self)
      end
    end
133
  end
134
end