activemodel 3.0.20 → 3.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/CHANGELOG +17 -73
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +5 -5
  4. data/lib/active_model.rb +2 -2
  5. data/lib/active_model/attribute_methods.rb +46 -53
  6. data/lib/active_model/callbacks.rb +2 -5
  7. data/lib/active_model/conversion.rb +0 -2
  8. data/lib/active_model/dirty.rb +3 -4
  9. data/lib/active_model/errors.rb +55 -56
  10. data/lib/active_model/lint.rb +2 -2
  11. data/lib/active_model/mass_assignment_security.rb +96 -47
  12. data/lib/active_model/naming.rb +55 -13
  13. data/lib/active_model/observer_array.rb +104 -0
  14. data/lib/active_model/observing.rb +53 -18
  15. data/lib/active_model/secure_password.rb +67 -0
  16. data/lib/active_model/serialization.rb +4 -11
  17. data/lib/active_model/serializers/json.rb +18 -18
  18. data/lib/active_model/serializers/xml.rb +26 -5
  19. data/lib/active_model/translation.rb +4 -11
  20. data/lib/active_model/validations.rb +23 -23
  21. data/lib/active_model/validations/acceptance.rb +3 -5
  22. data/lib/active_model/validations/callbacks.rb +5 -19
  23. data/lib/active_model/validations/confirmation.rb +6 -5
  24. data/lib/active_model/validations/exclusion.rb +27 -3
  25. data/lib/active_model/validations/format.rb +38 -12
  26. data/lib/active_model/validations/inclusion.rb +30 -23
  27. data/lib/active_model/validations/length.rb +3 -1
  28. data/lib/active_model/validations/numericality.rb +4 -2
  29. data/lib/active_model/validations/presence.rb +3 -2
  30. data/lib/active_model/validations/validates.rb +23 -9
  31. data/lib/active_model/validations/with.rb +14 -2
  32. data/lib/active_model/validator.rb +16 -18
  33. data/lib/active_model/version.rb +3 -3
  34. metadata +71 -58
  35. checksums.yaml +0 -7
  36. data/lib/active_model/deprecated_error_methods.rb +0 -33
@@ -18,12 +18,12 @@ module ActiveModel
18
18
  #
19
19
  # This also provides the required class methods for hooking into the
20
20
  # Rails internationalization API, including being able to define a
21
- # class based i18n_scope and lookup_ancestors to find translations in
21
+ # class based +i18n_scope+ and +lookup_ancestors+ to find translations in
22
22
  # parent classes.
23
23
  module Translation
24
24
  include ActiveModel::Naming
25
25
 
26
- # Returns the i18n_scope for the class. Overwrite if you want custom lookup.
26
+ # Returns the +i18n_scope+ for the class. Overwrite if you want custom lookup.
27
27
  def i18n_scope
28
28
  :activemodel
29
29
  end
@@ -44,9 +44,8 @@ module ActiveModel
44
44
  # Specify +options+ with additional translating options.
45
45
  def human_attribute_name(attribute, options = {})
46
46
  defaults = lookup_ancestors.map do |klass|
47
- [:"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}",
48
- :"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key.to_s.tr('.', '/')}.#{attribute}"]
49
- end.flatten
47
+ :"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}"
48
+ end
50
49
 
51
50
  defaults << :"attributes.#{attribute}"
52
51
  defaults << options.delete(:default) if options[:default]
@@ -55,11 +54,5 @@ module ActiveModel
55
54
  options.reverse_merge! :count => 1, :default => defaults
56
55
  I18n.translate(defaults.shift, options)
57
56
  end
58
-
59
- # Model.human_name is deprecated. Use Model.model_name.human instead.
60
- def human_name(*args)
61
- ActiveSupport::Deprecation.warn("human_name has been deprecated, please use model_name.human instead", caller[0,5])
62
- model_name.human(*args)
63
- end
64
57
  end
65
58
  end
@@ -36,8 +36,8 @@ module ActiveModel
36
36
  # person.invalid? # => true
37
37
  # person.errors # => #<OrderedHash {:first_name=>["starts with z."]}>
38
38
  #
39
- # Note that ActiveModel::Validations automatically adds an +errors+ method
40
- # to your instances initialized with a new ActiveModel::Errors object, so
39
+ # Note that <tt>ActiveModel::Validations</tt> automatically adds an +errors+ method
40
+ # to your instances initialized with a new <tt>ActiveModel::Errors</tt> object, so
41
41
  # there is no need for you to do this manually.
42
42
  #
43
43
  module Validations
@@ -71,8 +71,8 @@ module ActiveModel
71
71
  # end
72
72
  #
73
73
  # Options:
74
- # * <tt>:on</tt> - Specifies when this validation is active (default is
75
- # <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
74
+ # * <tt>:on</tt> - Specifies the context where this validation is active
75
+ # (e.g. <tt>:on => :create</tt> or <tt>:on => :custom_validation_context</tt>)
76
76
  # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
77
77
  # * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
78
78
  # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
@@ -104,7 +104,7 @@ module ActiveModel
104
104
  # end
105
105
  # end
106
106
  #
107
- # Or with a block which is passed with the current record to be validated:
107
+ # With a block which is passed with the current record to be validated:
108
108
  #
109
109
  # class Comment
110
110
  # include ActiveModel::Validations
@@ -114,7 +114,17 @@ module ActiveModel
114
114
  # end
115
115
  #
116
116
  # def must_be_friends
117
- # errors.add(:base, ("Must be friends to leave a comment") unless commenter.friend_of?(commentee)
117
+ # errors.add(:base, "Must be friends to leave a comment") unless commenter.friend_of?(commentee)
118
+ # end
119
+ # end
120
+ #
121
+ # Or with a block where self points to the current record to be validated:
122
+ #
123
+ # class Comment
124
+ # include ActiveModel::Validations
125
+ #
126
+ # validate do
127
+ # errors.add(:base, "Must be friends to leave a comment") unless commenter.friend_of?(commentee)
118
128
  # end
119
129
  # end
120
130
  #
@@ -123,24 +133,12 @@ module ActiveModel
123
133
  if options.key?(:on)
124
134
  options = options.dup
125
135
  options[:if] = Array.wrap(options[:if])
126
- options[:if] << "validation_context == :#{options[:on]}"
136
+ options[:if].unshift("validation_context == :#{options[:on]}")
127
137
  end
128
138
  args << options
129
139
  set_callback(:validate, *args, &block)
130
140
  end
131
141
 
132
- [:create, :update].each do |type|
133
- class_eval <<-RUBY
134
- def validate_on_#{type}(*args, &block)
135
- msg = "validate_on_#{type} is deprecated. Please use validate(args, :on => :#{type})"
136
- ActiveSupport::Deprecation.warn(msg, caller)
137
- options = args.extract_options!
138
- options[:on] = :#{type}
139
- validate(*args.push(options), &block)
140
- end
141
- RUBY
142
- end
143
-
144
142
  # List all validators that are being used to validate the model using
145
143
  # +validates_with+ method.
146
144
  def validators
@@ -148,8 +146,10 @@ module ActiveModel
148
146
  end
149
147
 
150
148
  # List all validators that being used to validate a specific attribute.
151
- def validators_on(attribute)
152
- _validators[attribute.to_sym]
149
+ def validators_on(*attributes)
150
+ attributes.map do |attribute|
151
+ _validators[attribute.to_sym]
152
+ end.flatten
153
153
  end
154
154
 
155
155
  # Check if method is an attribute method or not.
@@ -165,7 +165,7 @@ module ActiveModel
165
165
  end
166
166
  end
167
167
 
168
- # Returns the Errors object that holds all information about attribute error messages.
168
+ # Returns the +Errors+ object that holds all information about attribute error messages.
169
169
  def errors
170
170
  @errors ||= Errors.new(self)
171
171
  end
@@ -209,7 +209,7 @@ module ActiveModel
209
209
  protected
210
210
 
211
211
  def run_validations!
212
- _run_validate_callbacks
212
+ run_callbacks :validate
213
213
  errors.empty?
214
214
  end
215
215
  end
@@ -14,8 +14,6 @@ module ActiveModel
14
14
  end
15
15
 
16
16
  def setup(klass)
17
- # Note: instance_methods.map(&:to_s) is important for 1.9 compatibility
18
- # as instance_methods returns symbols unlike 1.8 which returns strings.
19
17
  attr_readers = attributes.reject { |name| klass.attribute_method?(name) }
20
18
  attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") }
21
19
  klass.send(:attr_reader, *attr_readers)
@@ -39,9 +37,9 @@ module ActiveModel
39
37
  # Configuration options:
40
38
  # * <tt>:message</tt> - A custom error message (default is: "must be
41
39
  # accepted").
42
- # * <tt>:on</tt> - Specifies when this validation is active (default is
43
- # <tt>:save</tt>, other options are <tt>:create</tt> and
44
- # <tt>:update</tt>).
40
+ # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
41
+ # validation contexts by default (+nil+), other options are <tt>:create</tt>
42
+ # and <tt>:update</tt>.
45
43
  # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default
46
44
  # is true).
47
45
  # * <tt>:accept</tt> - Specifies value that is considered accepted.
@@ -28,12 +28,12 @@ module ActiveModel
28
28
 
29
29
  module ClassMethods
30
30
  def before_validation(*args, &block)
31
- options = args.extract_options!
31
+ options = args.last
32
32
  if options.is_a?(Hash) && options[:on]
33
33
  options[:if] = Array.wrap(options[:if])
34
- options[:if] << "self.validation_context == :#{options[:on]}"
34
+ options[:if].unshift("self.validation_context == :#{options[:on]}")
35
35
  end
36
- set_callback(:validation, :before, *(args << options), &block)
36
+ set_callback(:validation, :before, *args, &block)
37
37
  end
38
38
 
39
39
  def after_validation(*args, &block)
@@ -41,30 +41,16 @@ module ActiveModel
41
41
  options[:prepend] = true
42
42
  options[:if] = Array.wrap(options[:if])
43
43
  options[:if] << "!halted"
44
- options[:if] << "self.validation_context == :#{options[:on]}" if options[:on]
44
+ options[:if].unshift("self.validation_context == :#{options[:on]}") if options[:on]
45
45
  set_callback(:validation, :after, *(args << options), &block)
46
46
  end
47
-
48
- [:before, :after].each do |type|
49
- [:create, :update].each do |on|
50
- class_eval <<-RUBY
51
- def #{type}_validation_on_#{on}(*args, &block)
52
- msg = "#{type}_validation_on_#{on} is deprecated. Please use #{type}_validation(arguments, :on => :#{on}"
53
- ActiveSupport::Deprecation.warn(msg, caller)
54
- options = args.extract_options!
55
- options[:on] = :#{on}
56
- before_validation(*args.push(options), &block)
57
- end
58
- RUBY
59
- end
60
- end
61
47
  end
62
48
 
63
49
  protected
64
50
 
65
51
  # Overwrite run validations to include callbacks.
66
52
  def run_validations!
67
- _run_validation_callbacks { super }
53
+ run_callbacks(:validation) { super }
68
54
  end
69
55
  end
70
56
  end
@@ -4,9 +4,9 @@ module ActiveModel
4
4
  module Validations
5
5
  class ConfirmationValidator < EachValidator
6
6
  def validate_each(record, attribute, value)
7
- confirmed = record.send(:"#{attribute}_confirmation")
8
- return if confirmed.nil? || value == confirmed
9
- record.errors.add(attribute, :confirmation, options)
7
+ if (confirmed = record.send("#{attribute}_confirmation")) && (value != confirmed)
8
+ record.errors.add(attribute, :confirmation, options)
9
+ end
10
10
  end
11
11
 
12
12
  def setup(klass)
@@ -45,8 +45,9 @@ module ActiveModel
45
45
  # Configuration options:
46
46
  # * <tt>:message</tt> - A custom error message (default is: "doesn't match
47
47
  # confirmation").
48
- # * <tt>:on</tt> - Specifies when this validation is active (default is
49
- # <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
48
+ # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
49
+ # validation contexts by default (+nil+), other options are <tt>:create</tt>
50
+ # and <tt>:update</tt>.
50
51
  # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
51
52
  # if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
52
53
  # or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
@@ -1,18 +1,35 @@
1
+ require 'active_support/core_ext/range.rb'
2
+
1
3
  module ActiveModel
2
4
 
3
5
  # == Active Model Exclusion Validator
4
6
  module Validations
5
7
  class ExclusionValidator < EachValidator
8
+ ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " <<
9
+ "and must be supplied as the :in option of the configuration hash"
10
+
6
11
  def check_validity!
7
- raise ArgumentError, "An object with the method include? is required must be supplied as the " <<
8
- ":in option of the configuration hash" unless options[:in].respond_to?(:include?)
12
+ unless [:include?, :call].any? { |method| options[:in].respond_to?(method) }
13
+ raise ArgumentError, ERROR_MESSAGE
14
+ end
9
15
  end
10
16
 
11
17
  def validate_each(record, attribute, value)
12
- if options[:in].include?(value)
18
+ delimiter = options[:in]
19
+ exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter
20
+ if exclusions.send(inclusion_method(exclusions), value)
13
21
  record.errors.add(attribute, :exclusion, options.except(:in).merge!(:value => value))
14
22
  end
15
23
  end
24
+
25
+ private
26
+
27
+ # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the
28
+ # range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt>
29
+ # uses the previous logic of comparing a value with the range endpoints.
30
+ def inclusion_method(enumerable)
31
+ enumerable.is_a?(Range) ? :cover? : :include?
32
+ end
16
33
  end
17
34
 
18
35
  module HelperMethods
@@ -22,13 +39,20 @@ module ActiveModel
22
39
  # validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
23
40
  # validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
24
41
  # validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
42
+ # validates_exclusion_of :password, :in => lambda { |p| [p.username, p.first_name] }, :message => "should not be the same as your username or first name"
25
43
  # end
26
44
  #
27
45
  # Configuration options:
28
46
  # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of.
47
+ # This can be supplied as a proc or lambda which returns an enumerable. If the enumerable
48
+ # is a range the test is performed with <tt>Range#cover?</tt>
49
+ # (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
29
50
  # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved").
30
51
  # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
31
52
  # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
53
+ # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
54
+ # validation contexts by default (+nil+), other options are <tt>:create</tt>
55
+ # and <tt>:update</tt>.
32
56
  # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
33
57
  # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
34
58
  # method, proc or string should return or evaluate to a true or false value.
@@ -4,10 +4,12 @@ module ActiveModel
4
4
  module Validations
5
5
  class FormatValidator < EachValidator
6
6
  def validate_each(record, attribute, value)
7
- if options[:with] && value.to_s !~ options[:with]
8
- record.errors.add(attribute, :invalid, options.except(:with).merge!(:value => value))
9
- elsif options[:without] && value.to_s =~ options[:without]
10
- record.errors.add(attribute, :invalid, options.except(:without).merge!(:value => value))
7
+ if options[:with]
8
+ regexp = option_call(record, :with)
9
+ record_error(record, attribute, :with, value) if value.to_s !~ regexp
10
+ elsif options[:without]
11
+ regexp = option_call(record, :without)
12
+ record_error(record, attribute, :without, value) if value.to_s =~ regexp
11
13
  end
12
14
  end
13
15
 
@@ -16,12 +18,25 @@ module ActiveModel
16
18
  raise ArgumentError, "Either :with or :without must be supplied (but not both)"
17
19
  end
18
20
 
19
- if options[:with] && !options[:with].is_a?(Regexp)
20
- raise ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash"
21
- end
21
+ check_options_validity(options, :with)
22
+ check_options_validity(options, :without)
23
+ end
24
+
25
+ private
22
26
 
23
- if options[:without] && !options[:without].is_a?(Regexp)
24
- raise ArgumentError, "A regular expression must be supplied as the :without option of the configuration hash"
27
+ def option_call(record, name)
28
+ option = options[name]
29
+ option.respond_to?(:call) ? option.call(record) : option
30
+ end
31
+
32
+ def record_error(record, attribute, name, value)
33
+ record.errors.add(attribute, :invalid, options.except(name).merge!(:value => value))
34
+ end
35
+
36
+ def check_options_validity(options, name)
37
+ option = options[name]
38
+ if option && !option.is_a?(Regexp) && !option.respond_to?(:call)
39
+ raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}"
25
40
  end
26
41
  end
27
42
  end
@@ -40,18 +55,29 @@ module ActiveModel
40
55
  # validates_format_of :email, :without => /NOSPAM/
41
56
  # end
42
57
  #
58
+ # You can also provide a proc or lambda which will determine the regular expression that will be used to validate the attribute
59
+ #
60
+ # class Person < ActiveRecord::Base
61
+ # # Admin can have number as a first letter in their screen name
62
+ # validates_format_of :screen_name, :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\Z/i : /\A[a-z][a-z0-9_\-]*\Z/i }
63
+ # end
64
+ #
43
65
  # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
44
66
  #
45
- # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option. In addition, both must be a regular expression,
46
- # or else an exception will be raised.
67
+ # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option. In addition, both must be a regular expression
68
+ # or a proc or lambda, or else an exception will be raised.
47
69
  #
48
70
  # Configuration options:
49
71
  # * <tt>:message</tt> - A custom error message (default is: "is invalid").
50
72
  # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
51
73
  # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
52
74
  # * <tt>:with</tt> - Regular expression that if the attribute matches will result in a successful validation.
75
+ # This can be provided as a proc or lambda returning regular expression which will be called at runtime.
53
76
  # * <tt>:without</tt> - Regular expression that if the attribute does not match will result in a successful validation.
54
- # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
77
+ # This can be provided as a proc or lambda returning regular expression which will be called at runtime.
78
+ # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
79
+ # validation contexts by default (+nil+), other options are <tt>:create</tt>
80
+ # and <tt>:update</tt>.
55
81
  # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
56
82
  # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
57
83
  # method, proc or string should return or evaluate to a true or false value.
@@ -1,35 +1,35 @@
1
+ require 'active_support/core_ext/range.rb'
2
+
1
3
  module ActiveModel
2
4
 
3
5
  # == Active Model Inclusion Validator
4
6
  module Validations
5
7
  class InclusionValidator < EachValidator
8
+ ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " <<
9
+ "and must be supplied as the :in option of the configuration hash"
10
+
6
11
  def check_validity!
7
- raise ArgumentError, "An object with the method include? is required must be supplied as the " <<
8
- ":in option of the configuration hash" unless options[:in].respond_to?(:include?)
12
+ unless [:include?, :call].any?{ |method| options[:in].respond_to?(method) }
13
+ raise ArgumentError, ERROR_MESSAGE
14
+ end
9
15
  end
10
16
 
11
- # On Ruby 1.9 Range#include? checks all possible values in the range for equality,
12
- # so it may be slow for large ranges. The new Range#cover? uses the previous logic
13
- # of comparing a value with the range endpoints.
14
- if (1..2).respond_to?(:cover?)
15
- def validate_each(record, attribute, value)
16
- included = if options[:in].is_a?(Range)
17
- options[:in].cover?(value)
18
- else
19
- options[:in].include?(value)
20
- end
21
-
22
- unless included
23
- record.errors.add(attribute, :inclusion, options.except(:in).merge!(:value => value))
24
- end
25
- end
26
- else
27
- def validate_each(record, attribute, value)
28
- unless options[:in].include?(value)
29
- record.errors.add(attribute, :inclusion, options.except(:in).merge!(:value => value))
30
- end
17
+ def validate_each(record, attribute, value)
18
+ delimiter = options[:in]
19
+ exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter
20
+ unless exclusions.send(inclusion_method(exclusions), value)
21
+ record.errors.add(attribute, :inclusion, options.except(:in).merge!(:value => value))
31
22
  end
32
23
  end
24
+
25
+ private
26
+
27
+ # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the
28
+ # range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt>
29
+ # uses the previous logic of comparing a value with the range endpoints.
30
+ def inclusion_method(enumerable)
31
+ enumerable.is_a?(Range) ? :cover? : :include?
32
+ end
33
33
  end
34
34
 
35
35
  module HelperMethods
@@ -39,13 +39,20 @@ module ActiveModel
39
39
  # validates_inclusion_of :gender, :in => %w( m f )
40
40
  # validates_inclusion_of :age, :in => 0..99
41
41
  # validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %{value} is not included in the list"
42
+ # validates_inclusion_of :states, :in => lambda{ |person| STATES[person.country] }
42
43
  # end
43
44
  #
44
45
  # Configuration options:
45
- # * <tt>:in</tt> - An enumerable object of available items.
46
+ # * <tt>:in</tt> - An enumerable object of available items. This can be
47
+ # supplied as a proc or lambda which returns an enumerable. If the enumerable
48
+ # is a range the test is performed with <tt>Range#cover?</tt>
49
+ # (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
46
50
  # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list").
47
51
  # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
48
52
  # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
53
+ # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
54
+ # validation contexts by default (+nil+), other options are <tt>:create</tt>
55
+ # and <tt>:update</tt>.
49
56
  # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
50
57
  # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
51
58
  # method, proc or string should return or evaluate to a true or false value.