activemodel 3.2.22.5 → 4.0.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.
- 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
@@ -0,0 +1,31 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
# == Active Model Absence Validator
|
4
|
+
class AbsenceValidator < EachValidator #:nodoc:
|
5
|
+
def validate_each(record, attr_name, value)
|
6
|
+
record.errors.add(attr_name, :present, options) if value.present?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module HelperMethods
|
11
|
+
# Validates that the specified attributes are blank (as defined by
|
12
|
+
# Object#blank?). Happens by default on save.
|
13
|
+
#
|
14
|
+
# class Person < ActiveRecord::Base
|
15
|
+
# validates_absence_of :first_name
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# The first_name attribute must be in the object and it must be blank.
|
19
|
+
#
|
20
|
+
# Configuration options:
|
21
|
+
# * <tt>:message</tt> - A custom error message (default is: "must be blank").
|
22
|
+
#
|
23
|
+
# There is also a list of default options supported by every validator:
|
24
|
+
# +:if+, +:unless+, +:on+ and +:strict+.
|
25
|
+
# See <tt>ActiveModel::Validation#validates</tt> for more information
|
26
|
+
def validates_absence_of(*attr_names)
|
27
|
+
validates_with AbsenceValidator, _merge_attributes(attr_names)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module ActiveModel
|
2
|
-
|
2
|
+
|
3
3
|
module Validations
|
4
|
-
class AcceptanceValidator < EachValidator
|
4
|
+
class AcceptanceValidator < EachValidator # :nodoc:
|
5
5
|
def initialize(options)
|
6
|
-
super(
|
6
|
+
super({ :allow_nil => true, :accept => "1" }.merge!(options))
|
7
7
|
end
|
8
8
|
|
9
9
|
def validate_each(record, attribute, value)
|
@@ -22,11 +22,11 @@ module ActiveModel
|
|
22
22
|
|
23
23
|
module HelperMethods
|
24
24
|
# Encapsulates the pattern of wanting to validate the acceptance of a
|
25
|
-
# terms of service check box (or similar agreement).
|
25
|
+
# terms of service check box (or similar agreement).
|
26
26
|
#
|
27
27
|
# class Person < ActiveRecord::Base
|
28
28
|
# validates_acceptance_of :terms_of_service
|
29
|
-
# validates_acceptance_of :eula, :
|
29
|
+
# validates_acceptance_of :eula, message: 'must be abided'
|
30
30
|
# end
|
31
31
|
#
|
32
32
|
# If the database column does not exist, the +terms_of_service+ attribute
|
@@ -36,29 +36,17 @@ module ActiveModel
|
|
36
36
|
# Configuration options:
|
37
37
|
# * <tt>:message</tt> - A custom error message (default is: "must be
|
38
38
|
# accepted").
|
39
|
-
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
|
40
|
-
# validation contexts by default (+nil+), other options are <tt>:create</tt>
|
41
|
-
# and <tt>:update</tt>.
|
42
39
|
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default
|
43
|
-
# is true).
|
40
|
+
# is +true+).
|
44
41
|
# * <tt>:accept</tt> - Specifies value that is considered accepted.
|
45
42
|
# The default value is a string "1", which makes it easy to relate to
|
46
43
|
# an HTML checkbox. This should be set to +true+ if you are validating
|
47
44
|
# a database column, since the attribute is typecast from "1" to +true+
|
48
45
|
# before validation.
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
# value.
|
54
|
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
55
|
-
# determine if the validation should not occur (for example,
|
56
|
-
# <tt>:unless => :skip_validation</tt>, or
|
57
|
-
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
|
58
|
-
# The method, proc or string should return or evaluate to a true or
|
59
|
-
# false value.
|
60
|
-
# * <tt>:strict</tt> - Specifies whether validation should be strict.
|
61
|
-
# See <tt>ActiveModel::Validation#validates!</tt> for more information.
|
46
|
+
#
|
47
|
+
# There is also a list of default options supported by every validator:
|
48
|
+
# +:if+, +:unless+, +:on+ and +:strict+.
|
49
|
+
# See <tt>ActiveModel::Validation#validates</tt> for more information
|
62
50
|
def validates_acceptance_of(*attr_names)
|
63
51
|
validates_with AcceptanceValidator, _merge_attributes(attr_names)
|
64
52
|
end
|
@@ -1,47 +1,100 @@
|
|
1
|
-
require 'active_support/callbacks'
|
2
|
-
|
3
1
|
module ActiveModel
|
4
2
|
module Validations
|
3
|
+
# == Active \Model Validation Callbacks
|
4
|
+
#
|
5
|
+
# Provides an interface for any class to have +before_validation+ and
|
6
|
+
# +after_validation+ callbacks.
|
7
|
+
#
|
8
|
+
# First, include ActiveModel::Validations::Callbacks from the class you are
|
9
|
+
# creating:
|
10
|
+
#
|
11
|
+
# class MyModel
|
12
|
+
# include ActiveModel::Validations::Callbacks
|
13
|
+
#
|
14
|
+
# before_validation :do_stuff_before_validation
|
15
|
+
# after_validation :do_stuff_after_validation
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# Like other <tt>before_*</tt> callbacks if +before_validation+ returns
|
19
|
+
# +false+ then <tt>valid?</tt> will not be called.
|
5
20
|
module Callbacks
|
6
|
-
# == Active Model Validation callbacks
|
7
|
-
#
|
8
|
-
# Provides an interface for any class to have <tt>before_validation</tt> and
|
9
|
-
# <tt>after_validation</tt> callbacks.
|
10
|
-
#
|
11
|
-
# First, extend ActiveModel::Callbacks from the class you are creating:
|
12
|
-
#
|
13
|
-
# class MyModel
|
14
|
-
# include ActiveModel::Validations::Callbacks
|
15
|
-
#
|
16
|
-
# before_validation :do_stuff_before_validation
|
17
|
-
# after_validation :do_stuff_after_validation
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# Like other before_* callbacks if <tt>before_validation</tt> returns false
|
21
|
-
# then <tt>valid?</tt> will not be called.
|
22
21
|
extend ActiveSupport::Concern
|
23
22
|
|
24
23
|
included do
|
25
24
|
include ActiveSupport::Callbacks
|
26
|
-
define_callbacks :validation, :terminator => "result == false", :scope => [:kind, :name]
|
25
|
+
define_callbacks :validation, :terminator => "result == false", :skip_after_callbacks_if_terminated => true, :scope => [:kind, :name]
|
27
26
|
end
|
28
27
|
|
29
28
|
module ClassMethods
|
29
|
+
# Defines a callback that will get called right before validation
|
30
|
+
# happens.
|
31
|
+
#
|
32
|
+
# class Person
|
33
|
+
# include ActiveModel::Validations
|
34
|
+
# include ActiveModel::Validations::Callbacks
|
35
|
+
#
|
36
|
+
# attr_accessor :name
|
37
|
+
#
|
38
|
+
# validates_length_of :name, maximum: 6
|
39
|
+
#
|
40
|
+
# before_validation :remove_whitespaces
|
41
|
+
#
|
42
|
+
# private
|
43
|
+
#
|
44
|
+
# def remove_whitespaces
|
45
|
+
# name.strip!
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# person = Person.new
|
50
|
+
# person.name = ' bob '
|
51
|
+
# person.valid? # => true
|
52
|
+
# person.name # => "bob"
|
30
53
|
def before_validation(*args, &block)
|
31
54
|
options = args.last
|
32
55
|
if options.is_a?(Hash) && options[:on]
|
33
|
-
options[:if] = Array
|
34
|
-
options[:
|
56
|
+
options[:if] = Array(options[:if])
|
57
|
+
options[:on] = Array(options[:on])
|
58
|
+
options[:if].unshift("#{options[:on]}.include? self.validation_context")
|
35
59
|
end
|
36
60
|
set_callback(:validation, :before, *args, &block)
|
37
61
|
end
|
38
62
|
|
63
|
+
# Defines a callback that will get called right after validation
|
64
|
+
# happens.
|
65
|
+
#
|
66
|
+
# class Person
|
67
|
+
# include ActiveModel::Validations
|
68
|
+
# include ActiveModel::Validations::Callbacks
|
69
|
+
#
|
70
|
+
# attr_accessor :name, :status
|
71
|
+
#
|
72
|
+
# validates_presence_of :name
|
73
|
+
#
|
74
|
+
# after_validation :set_status
|
75
|
+
#
|
76
|
+
# private
|
77
|
+
#
|
78
|
+
# def set_status
|
79
|
+
# self.status = errors.empty?
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# person = Person.new
|
84
|
+
# person.name = ''
|
85
|
+
# person.valid? # => false
|
86
|
+
# person.status # => false
|
87
|
+
# person.name = 'bob'
|
88
|
+
# person.valid? # => true
|
89
|
+
# person.status # => true
|
39
90
|
def after_validation(*args, &block)
|
40
91
|
options = args.extract_options!
|
41
92
|
options[:prepend] = true
|
42
|
-
options[:if] = Array
|
43
|
-
options[:
|
44
|
-
|
93
|
+
options[:if] = Array(options[:if])
|
94
|
+
if options[:on]
|
95
|
+
options[:on] = Array(options[:on])
|
96
|
+
options[:if].unshift("#{options[:on]}.include? self.validation_context")
|
97
|
+
end
|
45
98
|
set_callback(:validation, :after, *(args << options), &block)
|
46
99
|
end
|
47
100
|
end
|
@@ -49,7 +102,7 @@ module ActiveModel
|
|
49
102
|
protected
|
50
103
|
|
51
104
|
# Overwrite run validations to include callbacks.
|
52
|
-
def run_validations!
|
105
|
+
def run_validations! #:nodoc:
|
53
106
|
run_callbacks(:validation) { super }
|
54
107
|
end
|
55
108
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'active_support/core_ext/range'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Validations
|
5
|
+
module Clusivity #:nodoc:
|
6
|
+
ERROR_MESSAGE = "An object with the method #include? or a proc, lambda or symbol is required, " \
|
7
|
+
"and must be supplied as the :in (or :within) option of the configuration hash"
|
8
|
+
|
9
|
+
def check_validity!
|
10
|
+
unless delimiter.respond_to?(:include?) || delimiter.respond_to?(:call) || delimiter.respond_to?(:to_sym)
|
11
|
+
raise ArgumentError, ERROR_MESSAGE
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def include?(record, value)
|
18
|
+
exclusions = if delimiter.respond_to?(:call)
|
19
|
+
delimiter.call(record)
|
20
|
+
elsif delimiter.respond_to?(:to_sym)
|
21
|
+
record.send(delimiter)
|
22
|
+
else
|
23
|
+
delimiter
|
24
|
+
end
|
25
|
+
|
26
|
+
exclusions.send(inclusion_method(exclusions), value)
|
27
|
+
end
|
28
|
+
|
29
|
+
def delimiter
|
30
|
+
@delimiter ||= options[:in] || options[:within]
|
31
|
+
end
|
32
|
+
|
33
|
+
# In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the
|
34
|
+
# range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt>
|
35
|
+
# uses the previous logic of comparing a value with the range endpoints.
|
36
|
+
def inclusion_method(enumerable)
|
37
|
+
enumerable.is_a?(Range) ? :cover? : :include?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module ActiveModel
|
2
|
-
|
2
|
+
|
3
3
|
module Validations
|
4
|
-
class ConfirmationValidator < EachValidator
|
4
|
+
class ConfirmationValidator < EachValidator # :nodoc:
|
5
5
|
def validate_each(record, attribute, value)
|
6
6
|
if (confirmed = record.send("#{attribute}_confirmation")) && (value != confirmed)
|
7
|
-
record.
|
7
|
+
human_attribute_name = record.class.human_attribute_name(attribute)
|
8
|
+
record.errors.add(:"#{attribute}_confirmation", :confirmation, options.merge(:attribute => human_attribute_name))
|
8
9
|
end
|
9
10
|
end
|
10
11
|
|
@@ -17,13 +18,13 @@ module ActiveModel
|
|
17
18
|
|
18
19
|
module HelperMethods
|
19
20
|
# Encapsulates the pattern of wanting to validate a password or email
|
20
|
-
# address field with a confirmation.
|
21
|
+
# address field with a confirmation.
|
21
22
|
#
|
22
23
|
# Model:
|
23
24
|
# class Person < ActiveRecord::Base
|
24
25
|
# validates_confirmation_of :user_name, :password
|
25
26
|
# validates_confirmation_of :email_address,
|
26
|
-
# :
|
27
|
+
# message: 'should match confirmation'
|
27
28
|
# end
|
28
29
|
#
|
29
30
|
# View:
|
@@ -36,29 +37,18 @@ module ActiveModel
|
|
36
37
|
# attribute.
|
37
38
|
#
|
38
39
|
# NOTE: This check is performed only if +password_confirmation+ is not
|
39
|
-
# +nil
|
40
|
-
#
|
40
|
+
# +nil+. To require confirmation, make sure to add a presence check for
|
41
|
+
# the confirmation attribute:
|
41
42
|
#
|
42
|
-
# validates_presence_of :password_confirmation, :
|
43
|
+
# validates_presence_of :password_confirmation, if: :password_changed?
|
43
44
|
#
|
44
45
|
# Configuration options:
|
45
46
|
# * <tt>:message</tt> - A custom error message (default is: "doesn't match
|
46
47
|
# confirmation").
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
|
52
|
-
# or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
53
|
-
# method, proc or string should return or evaluate to a true or false
|
54
|
-
# value.
|
55
|
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
56
|
-
# determine if the validation should not occur (e.g.
|
57
|
-
# <tt>:unless => :skip_validation</tt>, or
|
58
|
-
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
59
|
-
# method, proc or string should return or evaluate to a true or false value.
|
60
|
-
# * <tt>:strict</tt> - Specifies whether validation should be strict.
|
61
|
-
# See <tt>ActiveModel::Validation#validates!</tt> for more information.
|
48
|
+
#
|
49
|
+
# There is also a list of default options supported by every validator:
|
50
|
+
# +:if+, +:unless+, +:on+ and +:strict+.
|
51
|
+
# See <tt>ActiveModel::Validation#validates</tt> for more information
|
62
52
|
def validates_confirmation_of(*attr_names)
|
63
53
|
validates_with ConfirmationValidator, _merge_attributes(attr_names)
|
64
54
|
end
|
@@ -1,76 +1,47 @@
|
|
1
|
-
require
|
1
|
+
require "active_model/validations/clusivity"
|
2
2
|
|
3
3
|
module ActiveModel
|
4
|
-
# == Active Model Exclusion Validator
|
5
|
-
module Validations
|
6
|
-
class ExclusionValidator < 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 ExclusionValidator < EachValidator # :nodoc:
|
7
|
+
include Clusivity
|
15
8
|
|
16
9
|
def validate_each(record, attribute, value)
|
17
|
-
|
18
|
-
if exclusions.send(inclusion_method(exclusions), value)
|
10
|
+
if include?(record, value)
|
19
11
|
record.errors.add(attribute, :exclusion, 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
|
39
|
-
# Validates that the value of the specified attribute is not in a
|
40
|
-
# enumerable object.
|
17
|
+
# Validates that the value of the specified attribute is not in a
|
18
|
+
# particular enumerable object.
|
41
19
|
#
|
42
20
|
# class Person < ActiveRecord::Base
|
43
|
-
# validates_exclusion_of :username, :
|
44
|
-
# validates_exclusion_of :age, :
|
45
|
-
# validates_exclusion_of :format, :
|
46
|
-
# validates_exclusion_of :password, :
|
47
|
-
# :
|
21
|
+
# validates_exclusion_of :username, in: %w( admin superuser ), message: "You don't belong here"
|
22
|
+
# validates_exclusion_of :age, in: 30..60, message: 'This site is only for under 30 and over 60'
|
23
|
+
# validates_exclusion_of :format, in: %w( mov avi ), message: "extension %{value} is not allowed"
|
24
|
+
# validates_exclusion_of :password, in: ->(person) { [person.username, person.first_name] },
|
25
|
+
# message: 'should not be the same as your username or first name'
|
26
|
+
# validates_exclusion_of :karma, in: :reserved_karmas
|
48
27
|
# end
|
49
28
|
#
|
50
29
|
# Configuration options:
|
51
|
-
# * <tt>:in</tt> - An enumerable object of items that the value shouldn't
|
52
|
-
# part of. This can be supplied as a proc or
|
53
|
-
# If the enumerable is a range the test is performed with
|
54
|
-
# (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
|
30
|
+
# * <tt>:in</tt> - An enumerable object of items that the value shouldn't
|
31
|
+
# be part of. This can be supplied as a proc, lambda or symbol which returns an
|
32
|
+
# enumerable. If the enumerable is a range the test is performed with
|
55
33
|
# * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
|
56
|
-
#
|
57
|
-
# * <tt>:
|
58
|
-
#
|
34
|
+
# <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>.
|
35
|
+
# * <tt>:message</tt> - Specifies a custom error message (default is: "is
|
36
|
+
# reserved").
|
37
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the
|
38
|
+
# attribute is +nil+ (default is +false+).
|
59
39
|
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the
|
60
|
-
# attribute is blank
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
# 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 if
|
69
|
-
# 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
|
+
# attribute is blank(default is +false+).
|
41
|
+
#
|
42
|
+
# There is also a list of default options supported by every validator:
|
43
|
+
# +:if+, +:unless+, +:on+ and +:strict+.
|
44
|
+
# See <tt>ActiveModel::Validation#validates</tt> for more information
|
74
45
|
def validates_exclusion_of(*attr_names)
|
75
46
|
validates_with ExclusionValidator, _merge_attributes(attr_names)
|
76
47
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveModel
|
2
|
-
|
2
|
+
|
3
3
|
module Validations
|
4
|
-
class FormatValidator < EachValidator
|
4
|
+
class FormatValidator < EachValidator # :nodoc:
|
5
5
|
def validate_each(record, attribute, value)
|
6
6
|
if options[:with]
|
7
7
|
regexp = option_call(record, :with)
|
@@ -32,28 +32,38 @@ module ActiveModel
|
|
32
32
|
record.errors.add(attribute, :invalid, options.except(name).merge!(:value => value))
|
33
33
|
end
|
34
34
|
|
35
|
+
def regexp_using_multiline_anchors?(regexp)
|
36
|
+
regexp.source.start_with?("^") ||
|
37
|
+
(regexp.source.end_with?("$") && !regexp.source.end_with?("\\$"))
|
38
|
+
end
|
39
|
+
|
35
40
|
def check_options_validity(options, name)
|
36
41
|
option = options[name]
|
37
42
|
if option && !option.is_a?(Regexp) && !option.respond_to?(:call)
|
38
43
|
raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}"
|
44
|
+
elsif option && option.is_a?(Regexp) &&
|
45
|
+
regexp_using_multiline_anchors?(option) && options[:multiline] != true
|
46
|
+
raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \
|
47
|
+
"which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \
|
48
|
+
":multiline => true option?"
|
39
49
|
end
|
40
50
|
end
|
41
51
|
end
|
42
52
|
|
43
53
|
module HelperMethods
|
44
|
-
# Validates whether the value of the specified attribute is of the correct
|
45
|
-
# going by the regular expression provided.
|
46
|
-
# matches the regular expression:
|
54
|
+
# Validates whether the value of the specified attribute is of the correct
|
55
|
+
# form, going by the regular expression provided.You can require that the
|
56
|
+
# attribute matches the regular expression:
|
47
57
|
#
|
48
58
|
# class Person < ActiveRecord::Base
|
49
|
-
# validates_format_of :email, :
|
59
|
+
# validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create
|
50
60
|
# end
|
51
61
|
#
|
52
|
-
# Alternatively, you can require that the specified attribute does _not_
|
53
|
-
# the regular expression:
|
62
|
+
# Alternatively, you can require that the specified attribute does _not_
|
63
|
+
# match the regular expression:
|
54
64
|
#
|
55
65
|
# class Person < ActiveRecord::Base
|
56
|
-
# validates_format_of :email, :
|
66
|
+
# validates_format_of :email, without: /NOSPAM/
|
57
67
|
# end
|
58
68
|
#
|
59
69
|
# You can also provide a proc or lambda which will determine the regular
|
@@ -62,41 +72,41 @@ module ActiveModel
|
|
62
72
|
# class Person < ActiveRecord::Base
|
63
73
|
# # Admin can have number as a first letter in their screen name
|
64
74
|
# validates_format_of :screen_name,
|
65
|
-
# :
|
75
|
+
# with: ->(person) { person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\z/i : /\A[a-z][a-z0-9_\-]*\z/i }
|
66
76
|
# end
|
67
77
|
#
|
68
|
-
# Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the
|
69
|
-
# <tt>^</tt> and <tt>$</tt> match the start/end of a line.
|
78
|
+
# Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the
|
79
|
+
# string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
|
70
80
|
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
81
|
+
# Due to frequent misuse of <tt>^</tt> and <tt>$</tt>, you need to pass
|
82
|
+
# the <tt>multiline: true</tt> option in case you use any of these two
|
83
|
+
# anchors in the provided regular expression. In most cases, you should be
|
84
|
+
# using <tt>\A</tt> and <tt>\z</tt>.
|
85
|
+
#
|
86
|
+
# You must pass either <tt>:with</tt> or <tt>:without</tt> as an option.
|
87
|
+
# In addition, both must be a regular expression or a proc or lambda, or
|
88
|
+
# else an exception will be raised.
|
74
89
|
#
|
75
90
|
# Configuration options:
|
76
91
|
# * <tt>:message</tt> - A custom error message (default is: "is invalid").
|
77
|
-
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the
|
78
|
-
# is +nil+ (default is +false+).
|
92
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the
|
93
|
+
# attribute is +nil+ (default is +false+).
|
79
94
|
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the
|
80
95
|
# attribute is blank (default is +false+).
|
81
96
|
# * <tt>:with</tt> - Regular expression that if the attribute matches will
|
82
|
-
# result in a successful validation. This can be provided as a proc or
|
83
|
-
# returning regular expression which will be called at runtime.
|
84
|
-
# * <tt>:without</tt> - Regular expression that if the attribute does not match
|
85
|
-
# will result in a successful validation. This can be provided as a proc or
|
97
|
+
# result in a successful validation. This can be provided as a proc or
|
86
98
|
# lambda returning regular expression which will be called at runtime.
|
87
|
-
# * <tt>:
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
# or
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
# * <tt>:strict</tt> - Specifies whether validation should be strict.
|
99
|
-
# See <tt>ActiveModel::Validation#validates!</tt> for more information.
|
99
|
+
# * <tt>:without</tt> - Regular expression that if the attribute does not
|
100
|
+
# match will result in a successful validation. This can be provided as
|
101
|
+
# a proc or lambda returning regular expression which will be called at
|
102
|
+
# runtime.
|
103
|
+
# * <tt>:multiline</tt> - Set to true if your regular expression contains
|
104
|
+
# anchors that match the beginning or end of lines as opposed to the
|
105
|
+
# beginning or end of the string. These anchors are <tt>^</tt> and <tt>$</tt>.
|
106
|
+
#
|
107
|
+
# There is also a list of default options supported by every validator:
|
108
|
+
# +:if+, +:unless+, +:on+ and +:strict+.
|
109
|
+
# See <tt>ActiveModel::Validation#validates</tt> for more information
|
100
110
|
def validates_format_of(*attr_names)
|
101
111
|
validates_with FormatValidator, _merge_attributes(attr_names)
|
102
112
|
end
|