activemodel 3.2.22.5 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +85 -64
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +61 -24
  5. data/lib/active_model.rb +21 -11
  6. data/lib/active_model/attribute_methods.rb +150 -125
  7. data/lib/active_model/callbacks.rb +49 -34
  8. data/lib/active_model/conversion.rb +39 -19
  9. data/lib/active_model/deprecated_mass_assignment_security.rb +21 -0
  10. data/lib/active_model/dirty.rb +48 -32
  11. data/lib/active_model/errors.rb +176 -88
  12. data/lib/active_model/forbidden_attributes_protection.rb +27 -0
  13. data/lib/active_model/lint.rb +42 -55
  14. data/lib/active_model/locale/en.yml +3 -1
  15. data/lib/active_model/model.rb +97 -0
  16. data/lib/active_model/naming.rb +191 -51
  17. data/lib/active_model/railtie.rb +11 -1
  18. data/lib/active_model/secure_password.rb +55 -25
  19. data/lib/active_model/serialization.rb +51 -27
  20. data/lib/active_model/serializers/json.rb +83 -46
  21. data/lib/active_model/serializers/xml.rb +46 -12
  22. data/lib/active_model/test_case.rb +0 -12
  23. data/lib/active_model/translation.rb +9 -10
  24. data/lib/active_model/validations.rb +154 -52
  25. data/lib/active_model/validations/absence.rb +31 -0
  26. data/lib/active_model/validations/acceptance.rb +10 -22
  27. data/lib/active_model/validations/callbacks.rb +78 -25
  28. data/lib/active_model/validations/clusivity.rb +41 -0
  29. data/lib/active_model/validations/confirmation.rb +13 -23
  30. data/lib/active_model/validations/exclusion.rb +26 -55
  31. data/lib/active_model/validations/format.rb +44 -34
  32. data/lib/active_model/validations/inclusion.rb +22 -52
  33. data/lib/active_model/validations/length.rb +48 -49
  34. data/lib/active_model/validations/numericality.rb +30 -32
  35. data/lib/active_model/validations/presence.rb +12 -22
  36. data/lib/active_model/validations/validates.rb +68 -36
  37. data/lib/active_model/validations/with.rb +28 -23
  38. data/lib/active_model/validator.rb +22 -22
  39. data/lib/active_model/version.rb +4 -4
  40. metadata +23 -24
  41. data/lib/active_model/mass_assignment_security.rb +0 -237
  42. data/lib/active_model/mass_assignment_security/permission_set.rb +0 -40
  43. data/lib/active_model/mass_assignment_security/sanitizer.rb +0 -59
  44. data/lib/active_model/observer_array.rb +0 -147
  45. data/lib/active_model/observing.rb +0 -252
@@ -1,38 +1,16 @@
1
- require 'active_support/core_ext/range'
1
+ require "active_model/validations/clusivity"
2
2
 
3
3
  module ActiveModel
4
- # == Active Model Inclusion Validator
5
- module Validations
6
- class InclusionValidator < EachValidator
7
- ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " <<
8
- "and must be supplied as the :in (or :within) option of the configuration hash"
9
4
 
10
- def check_validity!
11
- unless [:include?, :call].any?{ |method| delimiter.respond_to?(method) }
12
- raise ArgumentError, ERROR_MESSAGE
13
- end
14
- end
5
+ module Validations
6
+ class InclusionValidator < EachValidator # :nodoc:
7
+ include Clusivity
15
8
 
16
9
  def validate_each(record, attribute, value)
17
- exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter
18
- unless exclusions.send(inclusion_method(exclusions), value)
10
+ unless include?(record, value)
19
11
  record.errors.add(attribute, :inclusion, options.except(:in, :within).merge!(:value => value))
20
12
  end
21
13
  end
22
-
23
- private
24
-
25
- def delimiter
26
- @delimiter ||= options[:in] || options[:within]
27
- end
28
-
29
- # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible
30
- # values in the range for equality, so it may be slow for large ranges. The new
31
- # <tt>Range#cover?</tt> uses the previous logic of comparing a value with the
32
- # range endpoints.
33
- def inclusion_method(enumerable)
34
- enumerable.is_a?(Range) ? :cover? : :include?
35
- end
36
14
  end
37
15
 
38
16
  module HelperMethods
@@ -40,37 +18,29 @@ module ActiveModel
40
18
  # particular enumerable object.
41
19
  #
42
20
  # class Person < ActiveRecord::Base
43
- # validates_inclusion_of :gender, :in => %w( m f )
44
- # validates_inclusion_of :age, :in => 0..99
45
- # validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %{value} is not included in the list"
46
- # validates_inclusion_of :states, :in => lambda{ |person| STATES[person.country] }
21
+ # validates_inclusion_of :gender, in: %w( m f )
22
+ # validates_inclusion_of :age, in: 0..99
23
+ # validates_inclusion_of :format, in: %w( jpg gif png ), message: "extension %{value} is not included in the list"
24
+ # validates_inclusion_of :states, in: ->(person) { STATES[person.country] }
25
+ # validates_inclusion_of :karma, in: :available_karmas
47
26
  # end
48
27
  #
49
28
  # Configuration options:
50
29
  # * <tt>:in</tt> - An enumerable object of available items. This can be
51
- # supplied as a proc or lambda which returns an enumerable. If the enumerable
52
- # is a range the test is performed with <tt>Range#cover?</tt>
53
- # (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
30
+ # supplied as a proc, lambda or symbol which returns an enumerable. If the
31
+ # enumerable is a range the test is performed with <tt>Range#cover?</tt>,
32
+ # otherwise with <tt>include?</tt>.
54
33
  # * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
55
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is not
56
- # included in the list").
57
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
58
- # is +nil+ (default is +false+).
59
- # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
34
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is
35
+ # not included in the list").
36
+ # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the
37
+ # attribute is +nil+ (default is +false+).
38
+ # * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the
60
39
  # attribute is blank (default is +false+).
61
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
62
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
63
- # and <tt>:update</tt>.
64
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
65
- # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
66
- # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
67
- # or string should return or evaluate to a true or false value.
68
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
69
- # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
70
- # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
71
- # proc or string should return or evaluate to a true or false value.
72
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
73
- # See <tt>ActiveModel::Validation#validates!</tt> for more information.
40
+ #
41
+ # There is also a list of default options supported by every validator:
42
+ # +:if+, +:unless+, +:on+ and +:strict+.
43
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
74
44
  def validates_inclusion_of(*attr_names)
75
45
  validates_with InclusionValidator, _merge_attributes(attr_names)
76
46
  end
@@ -1,9 +1,8 @@
1
- require "active_support/core_ext/string/encoding"
2
-
3
1
  module ActiveModel
4
- # == Active Model Length Validator
2
+
3
+ # == Active \Model Length \Validator
5
4
  module Validations
6
- class LengthValidator < EachValidator
5
+ class LengthValidator < EachValidator # :nodoc:
7
6
  MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze
8
7
  CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
9
8
 
@@ -12,8 +11,11 @@ module ActiveModel
12
11
  def initialize(options)
13
12
  if range = (options.delete(:in) || options.delete(:within))
14
13
  raise ArgumentError, ":in and :within must be a Range" unless range.is_a?(Range)
15
- options[:minimum], options[:maximum] = range.begin, range.end
16
- options[:maximum] -= 1 if range.exclude_end?
14
+ options[:minimum], options[:maximum] = range.min, range.max
15
+ end
16
+
17
+ if options[:allow_blank] == false && options[:minimum].nil? && options[:is].nil?
18
+ options[:minimum] = 1
17
19
  end
18
20
 
19
21
  super
@@ -29,8 +31,8 @@ module ActiveModel
29
31
  keys.each do |key|
30
32
  value = options[key]
31
33
 
32
- unless value.is_a?(Integer) && value >= 0
33
- raise ArgumentError, ":#{key} must be a nonnegative Integer"
34
+ unless (value.is_a?(Integer) && value >= 0) || value == Float::INFINITY
35
+ raise ArgumentError, ":#{key} must be a nonnegative Integer or Infinity"
34
36
  end
35
37
  end
36
38
  end
@@ -38,12 +40,15 @@ module ActiveModel
38
40
  def validate_each(record, attribute, value)
39
41
  value = tokenize(value)
40
42
  value_length = value.respond_to?(:length) ? value.length : value.to_s.length
43
+ errors_options = options.except(*RESERVED_OPTIONS)
41
44
 
42
45
  CHECKS.each do |key, validity_check|
43
46
  next unless check_value = options[key]
44
- next if value_length.send(validity_check, check_value)
45
47
 
46
- errors_options = options.except(*RESERVED_OPTIONS)
48
+ if !value.nil? || skip_nil_check?(key)
49
+ next if value_length.send(validity_check, check_value)
50
+ end
51
+
47
52
  errors_options[:count] = check_value
48
53
 
49
54
  default_message = options[MESSAGES[key]]
@@ -56,67 +61,61 @@ module ActiveModel
56
61
  private
57
62
 
58
63
  def tokenize(value)
59
- if value.kind_of?(String)
60
- if options[:tokenizer]
61
- options[:tokenizer].call(value)
62
- elsif !value.encoding_aware?
63
- value.mb_chars
64
- end
64
+ if options[:tokenizer] && value.kind_of?(String)
65
+ options[:tokenizer].call(value)
65
66
  end || value
66
67
  end
68
+
69
+ def skip_nil_check?(key)
70
+ key == :maximum && options[:allow_nil].nil? && options[:allow_blank].nil?
71
+ end
67
72
  end
68
73
 
69
74
  module HelperMethods
70
- # Validates that the specified attribute matches the length restrictions supplied.
71
- # Only one option can be used at a time:
75
+
76
+ # Validates that the specified attribute matches the length restrictions
77
+ # supplied. Only one option can be used at a time:
72
78
  #
73
79
  # class Person < ActiveRecord::Base
74
- # validates_length_of :first_name, :maximum => 30
75
- # validates_length_of :last_name, :maximum => 30, :message => "less than 30 if you don't mind"
76
- # validates_length_of :fax, :in => 7..32, :allow_nil => true
77
- # validates_length_of :phone, :in => 7..32, :allow_blank => true
78
- # validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
79
- # validates_length_of :zip_code, :minimum => 5, :too_short => "please enter at least 5 characters"
80
- # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with 4 characters... don't play me."
81
- # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least 100 words.",
82
- # :tokenizer => lambda { |str| str.scan(/\w+/) }
80
+ # validates_length_of :first_name, maximum: 30
81
+ # validates_length_of :last_name, maximum: 30, message: "less than 30 if you don't mind"
82
+ # validates_length_of :fax, in: 7..32, allow_nil: true
83
+ # validates_length_of :phone, in: 7..32, allow_blank: true
84
+ # validates_length_of :user_name, within: 6..20, too_long: 'pick a shorter name', too_short: 'pick a longer name'
85
+ # validates_length_of :zip_code, minimum: 5, too_short: 'please enter at least 5 characters'
86
+ # validates_length_of :smurf_leader, is: 4, message: "papa is spelled with 4 characters... don't play me."
87
+ # validates_length_of :essay, minimum: 100, too_short: 'Your essay must be at least 100 words.',
88
+ # tokenizer: ->(str) { str.scan(/\w+/) }
83
89
  # end
84
90
  #
85
91
  # Configuration options:
86
92
  # * <tt>:minimum</tt> - The minimum size of the attribute.
87
- # * <tt>:maximum</tt> - The maximum size of the attribute.
93
+ # * <tt>:maximum</tt> - The maximum size of the attribute. Allows +nil+ by
94
+ # default if not used with :minimum.
88
95
  # * <tt>:is</tt> - The exact size of the attribute.
89
- # * <tt>:within</tt> - A range specifying the minimum and maximum size of the
90
- # attribute.
91
- # * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
96
+ # * <tt>:within</tt> - A range specifying the minimum and maximum size of
97
+ # the attribute.
98
+ # * <tt>:in</tt> - A synonym (or alias) for <tt>:within</tt>.
92
99
  # * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
93
100
  # * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
94
101
  # * <tt>:too_long</tt> - The error message if the attribute goes over the
95
102
  # maximum (default is: "is too long (maximum is %{count} characters)").
96
103
  # * <tt>:too_short</tt> - The error message if the attribute goes under the
97
104
  # minimum (default is: "is too short (min is %{count} characters)").
98
- # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method
99
- # and the attribute is the wrong size (default is: "is the wrong length
100
- # should be %{count} characters)").
105
+ # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt>
106
+ # method and the attribute is the wrong size (default is: "is the wrong
107
+ # length (should be %{count} characters)").
101
108
  # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
102
109
  # <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
103
110
  # <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
104
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
105
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
106
- # and <tt>:update</tt>.
107
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
108
- # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
109
- # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
110
- # or string should return or evaluate to a true or false value.
111
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
112
- # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
113
- # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
114
- # method, proc or string should return or evaluate to a true or false value.
115
111
  # * <tt>:tokenizer</tt> - Specifies how to split up the attribute string.
116
- # (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to count words
117
- # as in above example). Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters.
118
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
119
- # See <tt>ActiveModel::Validation#validates!</tt> for more information.
112
+ # (e.g. <tt>tokenizer: ->(str) { str.scan(/\w+/) }</tt> to count words
113
+ # as in above example). Defaults to <tt>->(value) { value.split(//) }</tt>
114
+ # which counts individual characters.
115
+ #
116
+ # There is also a list of default options supported by every validator:
117
+ # +:if+, +:unless+, +:on+ and +:strict+.
118
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
120
119
  def validates_length_of(*attr_names)
121
120
  validates_with LengthValidator, _merge_attributes(attr_names)
122
121
  end
@@ -1,10 +1,10 @@
1
1
  module ActiveModel
2
- # == Active Model Numericality Validator
2
+
3
3
  module Validations
4
- class NumericalityValidator < EachValidator
4
+ class NumericalityValidator < EachValidator # :nodoc:
5
5
  CHECKS = { :greater_than => :>, :greater_than_or_equal_to => :>=,
6
6
  :equal_to => :==, :less_than => :<, :less_than_or_equal_to => :<=,
7
- :odd => :odd?, :even => :even? }.freeze
7
+ :odd => :odd?, :even => :even?, :other_than => :!= }.freeze
8
8
 
9
9
  RESERVED_OPTIONS = CHECKS.keys + [:only_integer]
10
10
 
@@ -17,9 +17,9 @@ module ActiveModel
17
17
  end
18
18
 
19
19
  def validate_each(record, attr_name, value)
20
- before_type_cast = "#{attr_name}_before_type_cast"
20
+ before_type_cast = :"#{attr_name}_before_type_cast"
21
21
 
22
- raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast.to_sym)
22
+ raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast)
23
23
  raw_value ||= value
24
24
 
25
25
  return if options[:allow_nil] && raw_value.nil?
@@ -78,46 +78,44 @@ module ActiveModel
78
78
  end
79
79
 
80
80
  module HelperMethods
81
- # Validates whether the value of the specified attribute is numeric by trying to convert it to
82
- # a float with Kernel.Float (if <tt>only_integer</tt> is false) or applying it to the regular expression
83
- # <tt>/\A[\+\-]?\d+\Z/</tt> (if <tt>only_integer</tt> is set to true).
81
+ # Validates whether the value of the specified attribute is numeric by
82
+ # trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt>
83
+ # is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\Z/</tt>
84
+ # (if <tt>only_integer</tt> is set to +true+).
84
85
  #
85
86
  # class Person < ActiveRecord::Base
86
- # validates_numericality_of :value, :on => :create
87
+ # validates_numericality_of :value, on: :create
87
88
  # end
88
89
  #
89
90
  # Configuration options:
90
91
  # * <tt>:message</tt> - A custom error message (default is: "is not a number").
91
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
92
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
93
- # and <tt>:update</tt>.
94
- # * <tt>:only_integer</tt> - Specifies whether the value has to be an integer, e.g. an integral value (default is +false+).
92
+ # * <tt>:only_integer</tt> - Specifies whether the value has to be an
93
+ # integer, e.g. an integral value (default is +false+).
95
94
  # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is
96
95
  # +false+). Notice that for fixnum and float columns empty strings are
97
96
  # converted to +nil+.
98
97
  # * <tt>:greater_than</tt> - Specifies the value must be greater than the
99
98
  # supplied value.
100
- # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be greater
101
- # than or equal the supplied value.
102
- # * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied value.
103
- # * <tt>:less_than</tt> - Specifies the value must be less than the supplied
99
+ # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be
100
+ # greater than or equal the supplied value.
101
+ # * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied
104
102
  # value.
105
- # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less than
106
- # or equal the supplied value.
103
+ # * <tt>:less_than</tt> - Specifies the value must be less than the
104
+ # supplied value.
105
+ # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less
106
+ # than or equal the supplied value.
107
+ # * <tt>:other_than</tt> - Specifies the value must be other than the
108
+ # supplied value.
107
109
  # * <tt>:odd</tt> - Specifies the value must be an odd number.
108
110
  # * <tt>:even</tt> - Specifies the value must be an even number.
109
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
110
- # if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
111
- # or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method,
112
- # proc or string should return or evaluate to a true or false value.
113
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
114
- # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
115
- # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
116
- # proc or string should return or evaluate to a true or false value.
117
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
118
- # See <tt>ActiveModel::Validation#validates!</tt> for more information.
119
111
  #
120
- # The following checks can also be supplied with a proc or a symbol which corresponds to a method:
112
+ # There is also a list of default options supported by every validator:
113
+ # +:if+, +:unless+, +:on+ and +:strict+ .
114
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
115
+ #
116
+ # The following checks can also be supplied with a proc or a symbol which
117
+ # corresponds to a method:
118
+ #
121
119
  # * <tt>:greater_than</tt>
122
120
  # * <tt>:greater_than_or_equal_to</tt>
123
121
  # * <tt>:equal_to</tt>
@@ -127,8 +125,8 @@ module ActiveModel
127
125
  # For example:
128
126
  #
129
127
  # class Person < ActiveRecord::Base
130
- # validates_numericality_of :width, :less_than => Proc.new { |person| person.height }
131
- # validates_numericality_of :width, :greater_than => :minimum_weight
128
+ # validates_numericality_of :width, less_than: ->(person) { person.height }
129
+ # validates_numericality_of :width, greater_than: :minimum_weight
132
130
  # end
133
131
  def validates_numericality_of(*attr_names)
134
132
  validates_with NumericalityValidator, _merge_attributes(attr_names)
@@ -1,17 +1,16 @@
1
- require 'active_support/core_ext/object/blank'
2
1
 
3
2
  module ActiveModel
4
- # == Active Model Presence Validator
3
+
5
4
  module Validations
6
- class PresenceValidator < EachValidator
7
- def validate(record)
8
- record.errors.add_on_blank(attributes, options)
5
+ class PresenceValidator < EachValidator # :nodoc:
6
+ def validate_each(record, attr_name, value)
7
+ record.errors.add(attr_name, :blank, options) if value.blank?
9
8
  end
10
9
  end
11
10
 
12
11
  module HelperMethods
13
12
  # Validates that the specified attributes are not blank (as defined by
14
- # Object#blank?). Happens by default on save. Example:
13
+ # Object#blank?). Happens by default on save.
15
14
  #
16
15
  # class Person < ActiveRecord::Base
17
16
  # validates_presence_of :first_name
@@ -19,28 +18,19 @@ module ActiveModel
19
18
  #
20
19
  # The first_name attribute must be in the object and it cannot be blank.
21
20
  #
22
- # If you want to validate the presence of a boolean field (where the real values
23
- # are true and false), you will want to use <tt>validates_inclusion_of :field_name,
24
- # :in => [true, false]</tt>.
21
+ # If you want to validate the presence of a boolean field (where the real
22
+ # values are +true+ and +false+), you will want to use
23
+ # <tt>validates_inclusion_of :field_name, in: [true, false]</tt>.
25
24
  #
26
25
  # This is due to the way Object#blank? handles boolean values:
27
26
  # <tt>false.blank? # => true</tt>.
28
27
  #
29
28
  # Configuration options:
30
29
  # * <tt>:message</tt> - A custom error message (default is: "can't be blank").
31
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
32
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
33
- # and <tt>:update</tt>.
34
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
35
- # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
36
- # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
37
- # or string should return or evaluate to a true or false value.
38
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
39
- # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
40
- # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
41
- # proc or string should return or evaluate to a true or false value.
42
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
43
- # See <tt>ActiveModel::Validation#validates!</tt> for more information.
30
+ #
31
+ # There is also a list of default options supported by every validator:
32
+ # +:if+, +:unless+, +:on+ and +:strict+.
33
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
44
34
  def validates_presence_of(*attr_names)
45
35
  validates_with PresenceValidator, _merge_attributes(attr_names)
46
36
  end
@@ -1,7 +1,6 @@
1
1
  require 'active_support/core_ext/hash/slice'
2
2
 
3
3
  module ActiveModel
4
- # == Active Model validates method
5
4
  module Validations
6
5
  module ClassMethods
7
6
  # This method is a shortcut to all default validators and any custom
@@ -11,18 +10,18 @@ module ActiveModel
11
10
  #
12
11
  # Examples of using the default rails validators:
13
12
  #
14
- # validates :terms, :acceptance => true
15
- # validates :password, :confirmation => true
16
- # validates :username, :exclusion => { :in => %w(admin superuser) }
17
- # validates :email, :format => { :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create }
18
- # validates :age, :inclusion => { :in => 0..9 }
19
- # validates :first_name, :length => { :maximum => 30 }
20
- # validates :age, :numericality => true
21
- # validates :username, :presence => true
22
- # validates :username, :uniqueness => true
13
+ # validates :terms, acceptance: true
14
+ # validates :password, confirmation: true
15
+ # validates :username, exclusion: { in: %w(admin superuser) }
16
+ # validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, on: :create }
17
+ # validates :age, inclusion: { in: 0..9 }
18
+ # validates :first_name, length: { maximum: 30 }
19
+ # validates :age, numericality: true
20
+ # validates :username, presence: true
21
+ # validates :username, uniqueness: true
23
22
  #
24
23
  # The power of the +validates+ method comes when using custom validators
25
- # and default validators in one call for a given attribute e.g.
24
+ # and default validators in one call for a given attribute.
26
25
  #
27
26
  # class EmailValidator < ActiveModel::EachValidator
28
27
  # def validate_each(record, attribute, value)
@@ -35,12 +34,12 @@ module ActiveModel
35
34
  # include ActiveModel::Validations
36
35
  # attr_accessor :name, :email
37
36
  #
38
- # validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 100 }
39
- # validates :email, :presence => true, :email => true
37
+ # validates :name, presence: true, uniqueness: true, length: { maximum: 100 }
38
+ # validates :email, presence: true, email: true
40
39
  # end
41
40
  #
42
41
  # Validator classes may also exist within the class being validated
43
- # allowing custom modules of validators to be included as needed e.g.
42
+ # allowing custom modules of validators to be included as needed.
44
43
  #
45
44
  # class Film
46
45
  # include ActiveModel::Validations
@@ -51,43 +50,64 @@ module ActiveModel
51
50
  # end
52
51
  # end
53
52
  #
54
- # validates :name, :title => true
53
+ # validates :name, title: true
55
54
  # end
56
55
  #
57
- # Additionally validator classes may be in another namespace and still used within any class.
56
+ # Additionally validator classes may be in another namespace and still
57
+ # used within any class.
58
58
  #
59
59
  # validates :name, :'film/title' => true
60
60
  #
61
- # The validators hash can also handle regular expressions, ranges,
62
- # arrays and strings in shortcut form, e.g.
61
+ # The validators hash can also handle regular expressions, ranges, arrays
62
+ # and strings in shortcut form.
63
63
  #
64
- # validates :email, :format => /@/
65
- # validates :gender, :inclusion => %w(male female)
66
- # validates :password, :length => 6..20
64
+ # validates :email, format: /@/
65
+ # validates :gender, inclusion: %w(male female)
66
+ # validates :password, length: 6..20
67
67
  #
68
68
  # When using shortcut form, ranges and arrays are passed to your
69
- # validator's initializer as +options[:in]+ while other types including
70
- # regular expressions and strings are passed as +options[:with]+
69
+ # validator's initializer as <tt>options[:in]</tt> while other types
70
+ # including regular expressions and strings are passed as <tt>options[:with]</tt>.
71
71
  #
72
- # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+ and +:strict+
73
- # can be given to one specific validator, as a hash:
72
+ # There is also a list of options that could be used along with validators:
74
73
  #
75
- # validates :password, :presence => { :if => :password_required? }, :confirmation => true
74
+ # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
75
+ # validation contexts by default (+nil+), other options are <tt>:create</tt>
76
+ # and <tt>:update</tt>.
77
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
78
+ # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
79
+ # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
80
+ # proc or string should return or evaluate to a +true+ or +false+ value.
81
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
82
+ # if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
83
+ # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
84
+ # method, proc or string should return or evaluate to a +true+ or
85
+ # +false+ value.
86
+ # * <tt>:strict</tt> - if the <tt>:strict</tt> option is set to true
87
+ # will raise ActiveModel::StrictValidationFailed instead of adding the error.
88
+ # <tt>:strict</tt> option can also be set to any other exception.
76
89
  #
77
- # Or to all at the same time:
90
+ # Example:
78
91
  #
79
- # validates :password, :presence => true, :confirmation => true, :if => :password_required?
92
+ # validates :password, presence: true, confirmation: true, if: :password_required?
93
+ # validates :token, uniqueness: true, strict: TokenGenerationException
80
94
  #
95
+ #
96
+ # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+, +:strict+
97
+ # and +:message+ can be given to one specific validator, as a hash:
98
+ #
99
+ # validates :password, presence: { if: :password_required?, message: 'is forgotten.' }, confirmation: true
81
100
  def validates(*attributes)
82
- defaults = attributes.extract_options!
101
+ defaults = attributes.extract_options!.dup
83
102
  validations = defaults.slice!(*_validates_default_keys)
84
103
 
85
104
  raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
86
105
  raise ArgumentError, "You need to supply at least one validation" if validations.empty?
87
106
 
88
- defaults.merge!(:attributes => attributes)
107
+ defaults[:attributes] = attributes
89
108
 
90
109
  validations.each do |key, options|
110
+ next unless options
91
111
  key = "#{key.to_s.camelize}Validator"
92
112
 
93
113
  begin
@@ -100,12 +120,24 @@ module ActiveModel
100
120
  end
101
121
  end
102
122
 
103
- # This method is used to define validation that cannot be corrected by end
104
- # user and is considered exceptional. So each validator defined with bang
123
+ # This method is used to define validations that cannot be corrected by end
124
+ # users and are considered exceptional. So each validator defined with bang
105
125
  # or <tt>:strict</tt> option set to <tt>true</tt> will always raise
106
126
  # <tt>ActiveModel::StrictValidationFailed</tt> instead of adding error
107
- # when validation fails.
108
- # See <tt>validates</tt> for more information about validation itself.
127
+ # when validation fails. See <tt>validates</tt> for more information about
128
+ # the validation itself.
129
+ #
130
+ # class Person
131
+ # include ActiveModel::Validations
132
+ #
133
+ # attr_accessor :name
134
+ # validates! :name, presence: true
135
+ # end
136
+ #
137
+ # person = Person.new
138
+ # person.name = ''
139
+ # person.valid?
140
+ # # => ActiveModel::StrictValidationFailed: Name can't be blank
109
141
  def validates!(*attributes)
110
142
  options = attributes.extract_options!
111
143
  options[:strict] = true
@@ -116,11 +148,11 @@ module ActiveModel
116
148
 
117
149
  # When creating custom validators, it might be useful to be able to specify
118
150
  # additional default keys. This can be done by overwriting this method.
119
- def _validates_default_keys
151
+ def _validates_default_keys # :nodoc:
120
152
  [:if, :unless, :on, :allow_blank, :allow_nil , :strict]
121
153
  end
122
154
 
123
- def _parse_validates_options(options) #:nodoc:
155
+ def _parse_validates_options(options) # :nodoc:
124
156
  case options
125
157
  when TrueClass
126
158
  {}