activemodel 6.0.6 → 6.1.0.rc1
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 +48 -267
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/active_model/attribute.rb +15 -14
- data/lib/active_model/attribute_assignment.rb +3 -4
- data/lib/active_model/attribute_methods.rb +74 -38
- data/lib/active_model/attribute_mutation_tracker.rb +8 -5
- data/lib/active_model/attribute_set/builder.rb +80 -13
- data/lib/active_model/attribute_set.rb +18 -16
- data/lib/active_model/attributes.rb +20 -24
- data/lib/active_model/dirty.rb +12 -4
- data/lib/active_model/error.rb +207 -0
- data/lib/active_model/errors.rb +316 -208
- data/lib/active_model/gem_version.rb +3 -3
- data/lib/active_model/lint.rb +1 -1
- data/lib/active_model/naming.rb +2 -2
- data/lib/active_model/nested_error.rb +22 -0
- data/lib/active_model/railtie.rb +1 -1
- data/lib/active_model/secure_password.rb +14 -14
- data/lib/active_model/serialization.rb +9 -6
- data/lib/active_model/serializers/json.rb +7 -0
- data/lib/active_model/type/date_time.rb +2 -2
- data/lib/active_model/type/float.rb +2 -0
- data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +11 -7
- data/lib/active_model/type/helpers/numeric.rb +8 -3
- data/lib/active_model/type/helpers/time_value.rb +27 -17
- data/lib/active_model/type/helpers/timezone.rb +1 -1
- data/lib/active_model/type/immutable_string.rb +14 -10
- data/lib/active_model/type/integer.rb +11 -2
- data/lib/active_model/type/registry.rb +5 -0
- data/lib/active_model/type/string.rb +12 -2
- data/lib/active_model/type/value.rb +9 -1
- data/lib/active_model/validations/absence.rb +1 -1
- data/lib/active_model/validations/acceptance.rb +1 -1
- data/lib/active_model/validations/clusivity.rb +5 -1
- data/lib/active_model/validations/confirmation.rb +2 -2
- data/lib/active_model/validations/exclusion.rb +1 -1
- data/lib/active_model/validations/format.rb +2 -2
- data/lib/active_model/validations/inclusion.rb +1 -1
- data/lib/active_model/validations/length.rb +2 -2
- data/lib/active_model/validations/numericality.rb +48 -41
- data/lib/active_model/validations/presence.rb +1 -1
- data/lib/active_model/validations/validates.rb +6 -4
- data/lib/active_model/validations.rb +2 -2
- data/lib/active_model/validator.rb +7 -2
- data/lib/active_model.rb +2 -1
- metadata +15 -14
@@ -24,44 +24,24 @@ module ActiveModel
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def validate_each(record, attr_name, value)
|
28
|
-
|
29
|
-
|
30
|
-
if record.respond_to?(came_from_user)
|
31
|
-
if record.public_send(came_from_user)
|
32
|
-
raw_value = record.read_attribute_before_type_cast(attr_name)
|
33
|
-
elsif record.respond_to?(:read_attribute)
|
34
|
-
raw_value = record.read_attribute(attr_name)
|
35
|
-
end
|
36
|
-
else
|
37
|
-
before_type_cast = :"#{attr_name}_before_type_cast"
|
38
|
-
if record.respond_to?(before_type_cast)
|
39
|
-
raw_value = record.public_send(before_type_cast)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
raw_value ||= value
|
43
|
-
|
44
|
-
if record_attribute_changed_in_place?(record, attr_name)
|
45
|
-
raw_value = value
|
46
|
-
end
|
47
|
-
|
48
|
-
unless is_number?(raw_value)
|
49
|
-
record.errors.add(attr_name, :not_a_number, filtered_options(raw_value))
|
27
|
+
def validate_each(record, attr_name, value, precision: Float::DIG, scale: nil)
|
28
|
+
unless is_number?(value, precision, scale)
|
29
|
+
record.errors.add(attr_name, :not_a_number, **filtered_options(value))
|
50
30
|
return
|
51
31
|
end
|
52
32
|
|
53
|
-
if allow_only_integer?(record) && !is_integer?(
|
54
|
-
record.errors.add(attr_name, :not_an_integer, filtered_options(
|
33
|
+
if allow_only_integer?(record) && !is_integer?(value)
|
34
|
+
record.errors.add(attr_name, :not_an_integer, **filtered_options(value))
|
55
35
|
return
|
56
36
|
end
|
57
37
|
|
58
|
-
value = parse_as_number(
|
38
|
+
value = parse_as_number(value, precision, scale)
|
59
39
|
|
60
40
|
options.slice(*CHECKS.keys).each do |option, option_value|
|
61
41
|
case option
|
62
42
|
when :odd, :even
|
63
|
-
unless value.to_i.
|
64
|
-
record.errors.add(attr_name, option, filtered_options(value))
|
43
|
+
unless value.to_i.public_send(CHECKS[option])
|
44
|
+
record.errors.add(attr_name, option, **filtered_options(value))
|
65
45
|
end
|
66
46
|
else
|
67
47
|
case option_value
|
@@ -71,34 +51,38 @@ module ActiveModel
|
|
71
51
|
option_value = record.send(option_value)
|
72
52
|
end
|
73
53
|
|
74
|
-
option_value = parse_as_number(option_value)
|
54
|
+
option_value = parse_as_number(option_value, precision, scale)
|
75
55
|
|
76
|
-
unless value.
|
77
|
-
record.errors.add(attr_name, option, filtered_options(value).merge!(count: option_value))
|
56
|
+
unless value.public_send(CHECKS[option], option_value)
|
57
|
+
record.errors.add(attr_name, option, **filtered_options(value).merge!(count: option_value))
|
78
58
|
end
|
79
59
|
end
|
80
60
|
end
|
81
61
|
end
|
82
62
|
|
83
63
|
private
|
84
|
-
def
|
85
|
-
!parse_as_number(raw_value).nil?
|
86
|
-
rescue ArgumentError, TypeError
|
87
|
-
false
|
88
|
-
end
|
89
|
-
|
90
|
-
def parse_as_number(raw_value)
|
64
|
+
def parse_as_number(raw_value, precision, scale)
|
91
65
|
if raw_value.is_a?(Float)
|
92
|
-
raw_value
|
66
|
+
parse_float(raw_value, precision, scale)
|
93
67
|
elsif raw_value.is_a?(Numeric)
|
94
68
|
raw_value
|
95
69
|
elsif is_integer?(raw_value)
|
96
70
|
raw_value.to_i
|
97
71
|
elsif !is_hexadecimal_literal?(raw_value)
|
98
|
-
Kernel.Float(raw_value)
|
72
|
+
parse_float(Kernel.Float(raw_value), precision, scale)
|
99
73
|
end
|
100
74
|
end
|
101
75
|
|
76
|
+
def parse_float(raw_value, precision, scale)
|
77
|
+
(scale ? raw_value.truncate(scale) : raw_value).to_d(precision)
|
78
|
+
end
|
79
|
+
|
80
|
+
def is_number?(raw_value, precision, scale)
|
81
|
+
!parse_as_number(raw_value, precision, scale).nil?
|
82
|
+
rescue ArgumentError, TypeError
|
83
|
+
false
|
84
|
+
end
|
85
|
+
|
102
86
|
def is_integer?(raw_value)
|
103
87
|
INTEGER_REGEX.match?(raw_value.to_s)
|
104
88
|
end
|
@@ -124,6 +108,27 @@ module ActiveModel
|
|
124
108
|
end
|
125
109
|
end
|
126
110
|
|
111
|
+
def read_attribute_for_validation(record, attr_name)
|
112
|
+
return super if record_attribute_changed_in_place?(record, attr_name)
|
113
|
+
|
114
|
+
came_from_user = :"#{attr_name}_came_from_user?"
|
115
|
+
|
116
|
+
if record.respond_to?(came_from_user)
|
117
|
+
if record.public_send(came_from_user)
|
118
|
+
raw_value = record.public_send(:"#{attr_name}_before_type_cast")
|
119
|
+
elsif record.respond_to?(:read_attribute)
|
120
|
+
raw_value = record.read_attribute(attr_name)
|
121
|
+
end
|
122
|
+
else
|
123
|
+
before_type_cast = :"#{attr_name}_before_type_cast"
|
124
|
+
if record.respond_to?(before_type_cast)
|
125
|
+
raw_value = record.public_send(before_type_cast)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
raw_value || super
|
130
|
+
end
|
131
|
+
|
127
132
|
def record_attribute_changed_in_place?(record, attr_name)
|
128
133
|
record.respond_to?(:attribute_changed_in_place?) &&
|
129
134
|
record.attribute_changed_in_place?(attr_name.to_s)
|
@@ -134,7 +139,8 @@ module ActiveModel
|
|
134
139
|
# Validates whether the value of the specified attribute is numeric by
|
135
140
|
# trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt>
|
136
141
|
# is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\z/</tt>
|
137
|
-
# (if <tt>only_integer</tt> is set to +true+).
|
142
|
+
# (if <tt>only_integer</tt> is set to +true+). Precision of Kernel.Float values
|
143
|
+
# are guaranteed up to 15 digits.
|
138
144
|
#
|
139
145
|
# class Person < ActiveRecord::Base
|
140
146
|
# validates_numericality_of :value, on: :create
|
@@ -175,6 +181,7 @@ module ActiveModel
|
|
175
181
|
# * <tt>:less_than</tt>
|
176
182
|
# * <tt>:less_than_or_equal_to</tt>
|
177
183
|
# * <tt>:only_integer</tt>
|
184
|
+
# * <tt>:other_than</tt>
|
178
185
|
#
|
179
186
|
# For example:
|
180
187
|
#
|
@@ -4,7 +4,7 @@ module ActiveModel
|
|
4
4
|
module Validations
|
5
5
|
class PresenceValidator < EachValidator # :nodoc:
|
6
6
|
def validate_each(record, attr_name, value)
|
7
|
-
record.errors.add(attr_name, :blank, options) if value.blank?
|
7
|
+
record.errors.add(attr_name, :blank, **options) if value.blank?
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -12,6 +12,7 @@ module ActiveModel
|
|
12
12
|
#
|
13
13
|
# Examples of using the default rails validators:
|
14
14
|
#
|
15
|
+
# validates :username, absence: true
|
15
16
|
# validates :terms, acceptance: true
|
16
17
|
# validates :password, confirmation: true
|
17
18
|
# validates :username, exclusion: { in: %w(admin superuser) }
|
@@ -27,7 +28,7 @@ module ActiveModel
|
|
27
28
|
# class EmailValidator < ActiveModel::EachValidator
|
28
29
|
# def validate_each(record, attribute, value)
|
29
30
|
# record.errors.add attribute, (options[:message] || "is not an email") unless
|
30
|
-
#
|
31
|
+
# /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i.match?(value)
|
31
32
|
# end
|
32
33
|
# end
|
33
34
|
#
|
@@ -47,7 +48,7 @@ module ActiveModel
|
|
47
48
|
#
|
48
49
|
# class TitleValidator < ActiveModel::EachValidator
|
49
50
|
# def validate_each(record, attribute, value)
|
50
|
-
# record.errors.add attribute, "must start with 'the'" unless
|
51
|
+
# record.errors.add attribute, "must start with 'the'" unless /\Athe/i.match?(value)
|
51
52
|
# end
|
52
53
|
# end
|
53
54
|
#
|
@@ -63,7 +64,7 @@ module ActiveModel
|
|
63
64
|
# and strings in shortcut form.
|
64
65
|
#
|
65
66
|
# validates :email, format: /@/
|
66
|
-
# validates :role, inclusion: %(admin contributor)
|
67
|
+
# validates :role, inclusion: %w(admin contributor)
|
67
68
|
# validates :password, length: 6..20
|
68
69
|
#
|
69
70
|
# When using shortcut form, ranges and arrays are passed to your
|
@@ -112,7 +113,6 @@ module ActiveModel
|
|
112
113
|
defaults[:attributes] = attributes
|
113
114
|
|
114
115
|
validations.each do |key, options|
|
115
|
-
next unless options
|
116
116
|
key = "#{key.to_s.camelize}Validator"
|
117
117
|
|
118
118
|
begin
|
@@ -121,6 +121,8 @@ module ActiveModel
|
|
121
121
|
raise ArgumentError, "Unknown validator: '#{key}'"
|
122
122
|
end
|
123
123
|
|
124
|
+
next unless options
|
125
|
+
|
124
126
|
validates_with(validator, defaults.merge(_parse_validates_options(options)))
|
125
127
|
end
|
126
128
|
end
|
@@ -15,7 +15,7 @@ module ActiveModel
|
|
15
15
|
# attr_accessor :first_name, :last_name
|
16
16
|
#
|
17
17
|
# validates_each :first_name, :last_name do |record, attr, value|
|
18
|
-
# record.errors.add attr,
|
18
|
+
# record.errors.add attr, "starts with z." if value.start_with?("z")
|
19
19
|
# end
|
20
20
|
# end
|
21
21
|
#
|
@@ -61,7 +61,7 @@ module ActiveModel
|
|
61
61
|
# attr_accessor :first_name, :last_name
|
62
62
|
#
|
63
63
|
# validates_each :first_name, :last_name, allow_blank: true do |record, attr, value|
|
64
|
-
# record.errors.add attr,
|
64
|
+
# record.errors.add attr, "starts with z." if value.start_with?("z")
|
65
65
|
# end
|
66
66
|
# end
|
67
67
|
#
|
@@ -85,7 +85,7 @@ module ActiveModel
|
|
85
85
|
#
|
86
86
|
# It can be useful to access the class that is using that validator when there are prerequisites such
|
87
87
|
# as an +attr_accessor+ being present. This class is accessible via <tt>options[:class]</tt> in the constructor.
|
88
|
-
# To
|
88
|
+
# To set up your validator override the constructor.
|
89
89
|
#
|
90
90
|
# class MyValidator < ActiveModel::Validator
|
91
91
|
# def initialize(options={})
|
@@ -147,7 +147,7 @@ module ActiveModel
|
|
147
147
|
# override +validate_each+ with validation logic.
|
148
148
|
def validate(record)
|
149
149
|
attributes.each do |attribute|
|
150
|
-
value =
|
150
|
+
value = read_attribute_for_validation(record, attribute)
|
151
151
|
next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
|
152
152
|
validate_each(record, attribute, value)
|
153
153
|
end
|
@@ -164,6 +164,11 @@ module ActiveModel
|
|
164
164
|
# +ArgumentError+ when invalid options are supplied.
|
165
165
|
def check_validity!
|
166
166
|
end
|
167
|
+
|
168
|
+
private
|
169
|
+
def read_attribute_for_validation(record, attr_name)
|
170
|
+
record.read_attribute_for_validation(attr_name)
|
171
|
+
end
|
167
172
|
end
|
168
173
|
|
169
174
|
# +BlockValidator+ is a special +EachValidator+ which receives a block on initialization
|
data/lib/active_model.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2004-
|
4
|
+
# Copyright (c) 2004-2020 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
@@ -53,6 +53,7 @@ module ActiveModel
|
|
53
53
|
|
54
54
|
eager_autoload do
|
55
55
|
autoload :Errors
|
56
|
+
autoload :Error
|
56
57
|
autoload :RangeError, "active_model/errors"
|
57
58
|
autoload :StrictValidationFailed, "active_model/errors"
|
58
59
|
autoload :UnknownAttributeError, "active_model/errors"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activemodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.0.
|
4
|
+
version: 6.1.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 6.0.
|
19
|
+
version: 6.1.0.rc1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 6.0.
|
26
|
+
version: 6.1.0.rc1
|
27
27
|
description: A toolkit for building modeling frameworks like Active Record. Rich support
|
28
28
|
for attributes, callbacks, validations, serialization, internationalization, and
|
29
29
|
testing.
|
@@ -48,6 +48,7 @@ files:
|
|
48
48
|
- lib/active_model/callbacks.rb
|
49
49
|
- lib/active_model/conversion.rb
|
50
50
|
- lib/active_model/dirty.rb
|
51
|
+
- lib/active_model/error.rb
|
51
52
|
- lib/active_model/errors.rb
|
52
53
|
- lib/active_model/forbidden_attributes_protection.rb
|
53
54
|
- lib/active_model/gem_version.rb
|
@@ -55,6 +56,7 @@ files:
|
|
55
56
|
- lib/active_model/locale/en.yml
|
56
57
|
- lib/active_model/model.rb
|
57
58
|
- lib/active_model/naming.rb
|
59
|
+
- lib/active_model/nested_error.rb
|
58
60
|
- lib/active_model/railtie.rb
|
59
61
|
- lib/active_model/secure_password.rb
|
60
62
|
- lib/active_model/serialization.rb
|
@@ -102,12 +104,11 @@ licenses:
|
|
102
104
|
- MIT
|
103
105
|
metadata:
|
104
106
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
105
|
-
changelog_uri: https://github.com/rails/rails/blob/v6.0.
|
106
|
-
documentation_uri: https://api.rubyonrails.org/v6.0.
|
107
|
+
changelog_uri: https://github.com/rails/rails/blob/v6.1.0.rc1/activemodel/CHANGELOG.md
|
108
|
+
documentation_uri: https://api.rubyonrails.org/v6.1.0.rc1/
|
107
109
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
108
|
-
source_code_uri: https://github.com/rails/rails/tree/v6.0.
|
109
|
-
|
110
|
-
post_install_message:
|
110
|
+
source_code_uri: https://github.com/rails/rails/tree/v6.1.0.rc1/activemodel
|
111
|
+
post_install_message:
|
111
112
|
rdoc_options: []
|
112
113
|
require_paths:
|
113
114
|
- lib
|
@@ -118,12 +119,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
118
119
|
version: 2.5.0
|
119
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
121
|
requirements:
|
121
|
-
- - "
|
122
|
+
- - ">"
|
122
123
|
- !ruby/object:Gem::Version
|
123
|
-
version:
|
124
|
+
version: 1.3.1
|
124
125
|
requirements: []
|
125
|
-
rubygems_version: 3.
|
126
|
-
signing_key:
|
126
|
+
rubygems_version: 3.1.4
|
127
|
+
signing_key:
|
127
128
|
specification_version: 4
|
128
129
|
summary: A toolkit for building modeling frameworks (part of Rails).
|
129
130
|
test_files: []
|