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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +85 -64
- data/MIT-LICENSE +1 -1
- data/README.rdoc +61 -24
- data/lib/active_model.rb +21 -11
- data/lib/active_model/attribute_methods.rb +150 -125
- data/lib/active_model/callbacks.rb +49 -34
- data/lib/active_model/conversion.rb +39 -19
- data/lib/active_model/deprecated_mass_assignment_security.rb +21 -0
- data/lib/active_model/dirty.rb +48 -32
- data/lib/active_model/errors.rb +176 -88
- data/lib/active_model/forbidden_attributes_protection.rb +27 -0
- data/lib/active_model/lint.rb +42 -55
- data/lib/active_model/locale/en.yml +3 -1
- data/lib/active_model/model.rb +97 -0
- data/lib/active_model/naming.rb +191 -51
- data/lib/active_model/railtie.rb +11 -1
- data/lib/active_model/secure_password.rb +55 -25
- data/lib/active_model/serialization.rb +51 -27
- data/lib/active_model/serializers/json.rb +83 -46
- data/lib/active_model/serializers/xml.rb +46 -12
- data/lib/active_model/test_case.rb +0 -12
- data/lib/active_model/translation.rb +9 -10
- data/lib/active_model/validations.rb +154 -52
- data/lib/active_model/validations/absence.rb +31 -0
- data/lib/active_model/validations/acceptance.rb +10 -22
- data/lib/active_model/validations/callbacks.rb +78 -25
- data/lib/active_model/validations/clusivity.rb +41 -0
- data/lib/active_model/validations/confirmation.rb +13 -23
- data/lib/active_model/validations/exclusion.rb +26 -55
- data/lib/active_model/validations/format.rb +44 -34
- data/lib/active_model/validations/inclusion.rb +22 -52
- data/lib/active_model/validations/length.rb +48 -49
- data/lib/active_model/validations/numericality.rb +30 -32
- data/lib/active_model/validations/presence.rb +12 -22
- data/lib/active_model/validations/validates.rb +68 -36
- data/lib/active_model/validations/with.rb +28 -23
- data/lib/active_model/validator.rb +22 -22
- data/lib/active_model/version.rb +4 -4
- metadata +23 -24
- data/lib/active_model/mass_assignment_security.rb +0 -237
- data/lib/active_model/mass_assignment_security/permission_set.rb +0 -40
- data/lib/active_model/mass_assignment_security/sanitizer.rb +0 -59
- data/lib/active_model/observer_array.rb +0 -147
- data/lib/active_model/observing.rb +0 -252
@@ -1,38 +1,16 @@
|
|
1
|
-
require
|
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
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
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, :
|
44
|
-
# validates_inclusion_of :age, :
|
45
|
-
# validates_inclusion_of :format, :
|
46
|
-
# validates_inclusion_of :states, :
|
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
|
52
|
-
# is a range the test is performed with <tt>Range#cover?</tt
|
53
|
-
#
|
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
|
56
|
-
# included in the list").
|
57
|
-
# * <tt>:allow_nil</tt> - If set to true
|
58
|
-
# is +nil+ (default is +false+).
|
59
|
-
# * <tt>:allow_blank</tt> - If set to true
|
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
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
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
|
-
|
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.
|
16
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
71
|
-
#
|
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, :
|
75
|
-
# validates_length_of :last_name, :
|
76
|
-
# validates_length_of :fax, :
|
77
|
-
# validates_length_of :phone, :
|
78
|
-
# validates_length_of :user_name, :
|
79
|
-
# validates_length_of :zip_code, :
|
80
|
-
# validates_length_of :smurf_leader, :
|
81
|
-
# validates_length_of :essay, :
|
82
|
-
# :
|
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
|
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>
|
99
|
-
# and the attribute is the wrong size (default is: "is the wrong
|
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
|
117
|
-
# as in above example). Defaults to <tt
|
118
|
-
#
|
119
|
-
#
|
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
|
-
|
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
|
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
|
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
|
82
|
-
# a float with Kernel.Float (if <tt>only_integer</tt>
|
83
|
-
# <tt>/\A[\+\-]?\d+\Z/</tt>
|
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, :
|
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>:
|
92
|
-
#
|
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
|
101
|
-
# than or equal the supplied value.
|
102
|
-
# * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied
|
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>:
|
106
|
-
#
|
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
|
-
#
|
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, :
|
131
|
-
# validates_numericality_of :width, :
|
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
|
-
|
3
|
+
|
5
4
|
module Validations
|
6
|
-
class PresenceValidator < EachValidator
|
7
|
-
def
|
8
|
-
record.errors.
|
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.
|
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
|
23
|
-
# are true and false), you will want to use
|
24
|
-
# :in
|
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
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
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, :
|
15
|
-
# validates :password, :
|
16
|
-
# validates :username, :
|
17
|
-
# validates :email, :
|
18
|
-
# validates :age, :
|
19
|
-
# validates :first_name, :
|
20
|
-
# validates :age, :
|
21
|
-
# validates :username, :
|
22
|
-
# validates :username, :
|
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
|
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, :
|
39
|
-
# validates :email, :
|
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
|
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, :
|
53
|
+
# validates :name, title: true
|
55
54
|
# end
|
56
55
|
#
|
57
|
-
# Additionally validator classes may be in another namespace and still
|
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
|
-
#
|
61
|
+
# The validators hash can also handle regular expressions, ranges, arrays
|
62
|
+
# and strings in shortcut form.
|
63
63
|
#
|
64
|
-
# validates :email, :
|
65
|
-
# validates :gender, :
|
66
|
-
# validates :password, :
|
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
|
70
|
-
# regular expressions and strings are passed as
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
90
|
+
# Example:
|
78
91
|
#
|
79
|
-
# validates :password, :
|
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
|
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
|
104
|
-
#
|
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
|
-
#
|
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)
|
155
|
+
def _parse_validates_options(options) # :nodoc:
|
124
156
|
case options
|
125
157
|
when TrueClass
|
126
158
|
{}
|