activemodel 3.0.20 → 3.1.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.