activemodel 7.2.2 → 8.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 +50 -38
- data/lib/active_model/attribute_assignment.rb +22 -1
- data/lib/active_model/dirty.rb +2 -1
- data/lib/active_model/gem_version.rb +4 -4
- data/lib/active_model/secure_password.rb +44 -3
- data/lib/active_model/serialization.rb +21 -21
- data/lib/active_model/translation.rb +8 -2
- data/lib/active_model/type/helpers/time_value.rb +20 -44
- data/lib/active_model/validations.rb +42 -24
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 906d52ef894a9f6b8fc0eb97488a653bcf0c0b141747cf7a7d5e8dcedb65e929
|
4
|
+
data.tar.gz: '084df4c1c4a669a5d5c583bb3a579fdbe1be8f7f2bc4c24506797f9197250d3f'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: acdcc972d445a2d7576785d1b145d66f2a895a9e21e6b17acdc5ef78871e49aea0a49694d92efce03c030b82e69b176298ced1eb8244bdd836151dd9dfaa5068
|
7
|
+
data.tar.gz: 918efc3fb79b912bfbff1661cfec5f822d86f2c33a135389de8f8bba150196c85411db87fb17470bccfea852ff3cda3c5c19bdc336d85238040f99ee0374138d
|
data/CHANGELOG.md
CHANGED
@@ -1,61 +1,73 @@
|
|
1
|
-
## Rails
|
1
|
+
## Rails 8.0.0.beta1 (September 26, 2024) ##
|
2
2
|
|
3
|
-
*
|
3
|
+
* Make `ActiveModel::Serialization#read_attribute_for_serialization` public
|
4
4
|
|
5
|
-
|
5
|
+
*Sean Doyle*
|
6
6
|
|
7
|
-
|
8
|
-
class Person
|
9
|
-
include ActiveModel::AttributeMethods
|
10
|
-
|
11
|
-
define_attribute_methods :name
|
12
|
-
attr_accessor :name
|
7
|
+
* Add a default token generator for password reset tokens when using `has_secure_password`.
|
13
8
|
|
14
|
-
|
9
|
+
```ruby
|
10
|
+
class User < ApplicationRecord
|
11
|
+
has_secure_password
|
15
12
|
end
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
*Jean Boussier*
|
21
|
-
|
22
|
-
|
23
|
-
## Rails 7.2.1.2 (October 23, 2024) ##
|
14
|
+
user = User.create!(name: "david", password: "123", password_confirmation: "123")
|
15
|
+
token = user.password_reset_token
|
16
|
+
User.find_by_password_reset_token(token) # returns user
|
24
17
|
|
25
|
-
|
18
|
+
# 16 minutes later...
|
19
|
+
User.find_by_password_reset_token(token) # returns nil
|
26
20
|
|
21
|
+
# raises ActiveSupport::MessageVerifier::InvalidSignature since the token is expired
|
22
|
+
User.find_by_password_reset_token!(token)
|
23
|
+
```
|
27
24
|
|
28
|
-
|
29
|
-
|
30
|
-
* No changes.
|
25
|
+
*DHH*
|
31
26
|
|
27
|
+
* Add a load hook `active_model_translation` for `ActiveModel::Translation`.
|
32
28
|
|
33
|
-
|
29
|
+
*Shouichi Kamiya*
|
34
30
|
|
35
|
-
*
|
31
|
+
* Add `raise_on_missing_translations` option to `ActiveModel::Translation`.
|
32
|
+
When the option is set, `human_attribute_name` raises an error if a translation of the given attribute is missing.
|
36
33
|
|
34
|
+
```ruby
|
35
|
+
# ActiveModel::Translation.raise_on_missing_translations = false
|
36
|
+
Post.human_attribute_name("title")
|
37
|
+
=> "Title"
|
38
|
+
|
39
|
+
# ActiveModel::Translation.raise_on_missing_translations = true
|
40
|
+
Post.human_attribute_name("title")
|
41
|
+
=> Translation missing. Options considered were: (I18n::MissingTranslationData)
|
42
|
+
- en.activerecord.attributes.post.title
|
43
|
+
- en.attributes.title
|
44
|
+
|
45
|
+
raise exception.respond_to?(:to_exception) ? exception.to_exception : exception
|
46
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
47
|
+
```
|
37
48
|
|
38
|
-
|
49
|
+
*Shouichi Kamiya*
|
39
50
|
|
40
|
-
*
|
41
|
-
calculate minus minute value in TZ offset correctly.
|
51
|
+
* Introduce `ActiveModel::AttributeAssignment#attribute_writer_missing`
|
42
52
|
|
43
|
-
|
53
|
+
Provide instances with an opportunity to gracefully handle assigning to an
|
54
|
+
unknown attribute:
|
44
55
|
|
45
|
-
|
46
|
-
|
47
|
-
|
56
|
+
```ruby
|
57
|
+
class Rectangle
|
58
|
+
include ActiveModel::AttributeAssignment
|
48
59
|
|
49
|
-
|
50
|
-
class MyModel
|
51
|
-
include ActiveModel::Attributes
|
60
|
+
attr_accessor :length, :width
|
52
61
|
|
53
|
-
|
62
|
+
def attribute_writer_missing(name, value)
|
63
|
+
Rails.logger.warn "Tried to assign to unknown attribute #{name}"
|
54
64
|
end
|
65
|
+
end
|
55
66
|
|
56
|
-
|
57
|
-
|
67
|
+
rectangle = Rectangle.new
|
68
|
+
rectangle.assign_attributes(height: 10) # => Logs "Tried to assign to unknown attribute 'height'"
|
69
|
+
```
|
58
70
|
|
59
|
-
*
|
71
|
+
*Sean Doyle*
|
60
72
|
|
61
|
-
Please check [7-
|
73
|
+
Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/activemodel/CHANGELOG.md) for previous changes.
|
@@ -36,6 +36,27 @@ module ActiveModel
|
|
36
36
|
|
37
37
|
alias attributes= assign_attributes
|
38
38
|
|
39
|
+
# Like `BasicObject#method_missing`, `#attribute_writer_missing` is invoked
|
40
|
+
# when `#assign_attributes` is passed an unknown attribute name.
|
41
|
+
#
|
42
|
+
# By default, `#attribute_writer_missing` raises an UnknownAttributeError.
|
43
|
+
#
|
44
|
+
# class Rectangle
|
45
|
+
# include ActiveModel::AttributeAssignment
|
46
|
+
#
|
47
|
+
# attr_accessor :length, :width
|
48
|
+
#
|
49
|
+
# def attribute_writer_missing(name, value)
|
50
|
+
# Rails.logger.warn "Tried to assign to unknown attribute #{name}"
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# rectangle = Rectangle.new
|
55
|
+
# rectangle.assign_attributes(height: 10) # => Logs "Tried to assign to unknown attribute 'height'"
|
56
|
+
def attribute_writer_missing(name, value)
|
57
|
+
raise UnknownAttributeError.new(self, name)
|
58
|
+
end
|
59
|
+
|
39
60
|
private
|
40
61
|
def _assign_attributes(attributes)
|
41
62
|
attributes.each do |k, v|
|
@@ -50,7 +71,7 @@ module ActiveModel
|
|
50
71
|
if respond_to?(setter)
|
51
72
|
raise
|
52
73
|
else
|
53
|
-
|
74
|
+
attribute_writer_missing(k.to_s, v)
|
54
75
|
end
|
55
76
|
end
|
56
77
|
end
|
data/lib/active_model/dirty.rb
CHANGED
@@ -256,7 +256,8 @@ module ActiveModel
|
|
256
256
|
end
|
257
257
|
|
258
258
|
def as_json(options = {}) # :nodoc:
|
259
|
-
|
259
|
+
except = [*options[:except], "mutations_from_database", "mutations_before_last_save"]
|
260
|
+
options = options.merge except: except
|
260
261
|
super(options)
|
261
262
|
end
|
262
263
|
|
@@ -39,6 +39,10 @@ module ActiveModel
|
|
39
39
|
# <tt>validations: false</tt> as an argument. This allows complete
|
40
40
|
# customizability of validation behavior.
|
41
41
|
#
|
42
|
+
# Finally, a password reset token that's valid for 15 minutes after issue
|
43
|
+
# is automatically configured when +reset_token+ is set to true (which it is by default)
|
44
|
+
# and the object reponds to +generates_token_for+ (which Active Records do).
|
45
|
+
#
|
42
46
|
# To use +has_secure_password+, add bcrypt (~> 3.1.7) to your Gemfile:
|
43
47
|
#
|
44
48
|
# gem "bcrypt", "~> 3.1.7"
|
@@ -98,7 +102,18 @@ module ActiveModel
|
|
98
102
|
# account.is_guest = true
|
99
103
|
# account.valid? # => true
|
100
104
|
#
|
101
|
-
|
105
|
+
# ===== Using the password reset token
|
106
|
+
#
|
107
|
+
# user = User.create!(name: "david", password: "123", password_confirmation: "123")
|
108
|
+
# token = user.password_reset_token
|
109
|
+
# User.find_by_password_reset_token(token) # returns user
|
110
|
+
#
|
111
|
+
# # 16 minutes later...
|
112
|
+
# User.find_by_password_reset_token(token) # returns nil
|
113
|
+
#
|
114
|
+
# # raises ActiveSupport::MessageVerifier::InvalidSignature since the token is expired
|
115
|
+
# User.find_by_password_reset_token!(token)
|
116
|
+
def has_secure_password(attribute = :password, validations: true, reset_token: true)
|
102
117
|
# Load bcrypt gem only when has_secure_password is used.
|
103
118
|
# This is to avoid ActiveModel (and by extension the entire framework)
|
104
119
|
# being dependent on a binary library.
|
@@ -109,7 +124,7 @@ module ActiveModel
|
|
109
124
|
raise
|
110
125
|
end
|
111
126
|
|
112
|
-
include InstanceMethodsOnActivation.new(attribute)
|
127
|
+
include InstanceMethodsOnActivation.new(attribute, reset_token: reset_token)
|
113
128
|
|
114
129
|
if validations
|
115
130
|
include ActiveModel::Validations
|
@@ -142,11 +157,30 @@ module ActiveModel
|
|
142
157
|
|
143
158
|
validates_confirmation_of attribute, allow_blank: true
|
144
159
|
end
|
160
|
+
|
161
|
+
# Only generate tokens for records that are capable of doing so (Active Records, not vanilla Active Models)
|
162
|
+
if reset_token && respond_to?(:generates_token_for)
|
163
|
+
generates_token_for :"#{attribute}_reset", expires_in: 15.minutes do
|
164
|
+
public_send(:"#{attribute}_salt")&.last(10)
|
165
|
+
end
|
166
|
+
|
167
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
168
|
+
silence_redefinition_of_method :find_by_#{attribute}_reset_token
|
169
|
+
def self.find_by_#{attribute}_reset_token(token)
|
170
|
+
find_by_token_for(:#{attribute}_reset, token)
|
171
|
+
end
|
172
|
+
|
173
|
+
silence_redefinition_of_method :find_by_#{attribute}_reset_token!
|
174
|
+
def self.find_by_#{attribute}_reset_token!(token)
|
175
|
+
find_by_token_for!(:#{attribute}_reset, token)
|
176
|
+
end
|
177
|
+
RUBY
|
178
|
+
end
|
145
179
|
end
|
146
180
|
end
|
147
181
|
|
148
182
|
class InstanceMethodsOnActivation < Module
|
149
|
-
def initialize(attribute)
|
183
|
+
def initialize(attribute, reset_token:)
|
150
184
|
attr_reader attribute
|
151
185
|
|
152
186
|
define_method("#{attribute}=") do |unencrypted_password|
|
@@ -184,6 +218,13 @@ module ActiveModel
|
|
184
218
|
end
|
185
219
|
|
186
220
|
alias_method :authenticate, :authenticate_password if attribute == :password
|
221
|
+
|
222
|
+
if reset_token
|
223
|
+
# Returns the class-level configured reset token for the password.
|
224
|
+
define_method("#{attribute}_reset_token") do
|
225
|
+
generate_token_for(:"#{attribute}_reset")
|
226
|
+
end
|
227
|
+
end
|
187
228
|
end
|
188
229
|
end
|
189
230
|
end
|
@@ -29,8 +29,8 @@ module ActiveModel
|
|
29
29
|
# An +attributes+ hash must be defined and should contain any attributes you
|
30
30
|
# need to be serialized. Attributes must be strings, not symbols.
|
31
31
|
# When called, serializable hash will use instance methods that match the name
|
32
|
-
# of the attributes hash's keys. In order to override this behavior,
|
33
|
-
#
|
32
|
+
# of the attributes hash's keys. In order to override this behavior, override
|
33
|
+
# the +read_attribute_for_serialization+ method.
|
34
34
|
#
|
35
35
|
# ActiveModel::Serializers::JSON module automatically includes
|
36
36
|
# the +ActiveModel::Serialization+ module, so there is no need to
|
@@ -128,7 +128,7 @@ module ActiveModel
|
|
128
128
|
return serializable_attributes(attribute_names) if options.blank?
|
129
129
|
|
130
130
|
if only = options[:only]
|
131
|
-
attribute_names
|
131
|
+
attribute_names = Array(only).map(&:to_s) & attribute_names
|
132
132
|
elsif except = options[:except]
|
133
133
|
attribute_names -= Array(except).map(&:to_s)
|
134
134
|
end
|
@@ -148,29 +148,29 @@ module ActiveModel
|
|
148
148
|
hash
|
149
149
|
end
|
150
150
|
|
151
|
+
# Hook method defining how an attribute value should be retrieved for
|
152
|
+
# serialization. By default this is assumed to be an instance named after
|
153
|
+
# the attribute. Override this method in subclasses should you need to
|
154
|
+
# retrieve the value for a given attribute differently:
|
155
|
+
#
|
156
|
+
# class MyClass
|
157
|
+
# include ActiveModel::Serialization
|
158
|
+
#
|
159
|
+
# def initialize(data = {})
|
160
|
+
# @data = data
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# def read_attribute_for_serialization(key)
|
164
|
+
# @data[key]
|
165
|
+
# end
|
166
|
+
# end
|
167
|
+
alias :read_attribute_for_serialization :send
|
168
|
+
|
151
169
|
private
|
152
170
|
def attribute_names_for_serialization
|
153
171
|
attributes.keys
|
154
172
|
end
|
155
173
|
|
156
|
-
# Hook method defining how an attribute value should be retrieved for
|
157
|
-
# serialization. By default this is assumed to be an instance named after
|
158
|
-
# the attribute. Override this method in subclasses should you need to
|
159
|
-
# retrieve the value for a given attribute differently:
|
160
|
-
#
|
161
|
-
# class MyClass
|
162
|
-
# include ActiveModel::Serialization
|
163
|
-
#
|
164
|
-
# def initialize(data = {})
|
165
|
-
# @data = data
|
166
|
-
# end
|
167
|
-
#
|
168
|
-
# def read_attribute_for_serialization(key)
|
169
|
-
# @data[key]
|
170
|
-
# end
|
171
|
-
# end
|
172
|
-
alias :read_attribute_for_serialization :send
|
173
|
-
|
174
174
|
def serializable_attributes(attribute_names)
|
175
175
|
attribute_names.index_with { |n| read_attribute_for_serialization(n) }
|
176
176
|
end
|
@@ -22,6 +22,8 @@ module ActiveModel
|
|
22
22
|
module Translation
|
23
23
|
include ActiveModel::Naming
|
24
24
|
|
25
|
+
singleton_class.attr_accessor :raise_on_missing_translations
|
26
|
+
|
25
27
|
# Returns the +i18n_scope+ for the class. Override if you want custom lookup.
|
26
28
|
def i18n_scope
|
27
29
|
:activemodel
|
@@ -60,13 +62,17 @@ module ActiveModel
|
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
65
|
+
raise_on_missing = options.fetch(:raise, Translation.raise_on_missing_translations)
|
66
|
+
|
63
67
|
defaults << :"attributes.#{attribute}"
|
64
68
|
defaults << options[:default] if options[:default]
|
65
|
-
defaults << MISSING_TRANSLATION
|
69
|
+
defaults << MISSING_TRANSLATION unless raise_on_missing
|
66
70
|
|
67
|
-
translation = I18n.translate(defaults.shift, count: 1, **options, default: defaults)
|
71
|
+
translation = I18n.translate(defaults.shift, count: 1, raise: raise_on_missing, **options, default: defaults)
|
68
72
|
translation = attribute.humanize if translation == MISSING_TRANSLATION
|
69
73
|
translation
|
70
74
|
end
|
71
75
|
end
|
76
|
+
|
77
|
+
ActiveSupport.run_load_hooks(:active_model_translation, Translation)
|
72
78
|
end
|
@@ -69,56 +69,32 @@ module ActiveModel
|
|
69
69
|
\z
|
70
70
|
/x
|
71
71
|
|
72
|
-
if
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
::Time.new(string)
|
84
|
-
end
|
85
|
-
rescue ArgumentError
|
86
|
-
nil
|
87
|
-
end
|
88
|
-
else
|
89
|
-
def fast_string_to_time(string)
|
90
|
-
return unless string.include?("-") # Time.new("1234") # => 1234-01-01 00:00:00
|
91
|
-
|
92
|
-
if is_utc?
|
93
|
-
::Time.new(string, in: "UTC")
|
94
|
-
else
|
95
|
-
::Time.new(string)
|
96
|
-
end
|
97
|
-
rescue ArgumentError
|
98
|
-
nil
|
72
|
+
if Time.new(2000, 1, 1, 0, 0, 0, "-00:00").yday != 1 # Early 3.2.x had a bug
|
73
|
+
# BUG: Wrapping the Time object with Time.at because Time.new with `in:` in Ruby 3.2.0
|
74
|
+
# used to return an invalid Time object
|
75
|
+
# see: https://bugs.ruby-lang.org/issues/19292
|
76
|
+
def fast_string_to_time(string)
|
77
|
+
return unless string.include?("-") # Time.new("1234") # => 1234-01-01 00:00:00
|
78
|
+
|
79
|
+
if is_utc?
|
80
|
+
::Time.at(::Time.new(string, in: "UTC"))
|
81
|
+
else
|
82
|
+
::Time.new(string)
|
99
83
|
end
|
84
|
+
rescue ArgumentError
|
85
|
+
nil
|
100
86
|
end
|
101
87
|
else
|
102
88
|
def fast_string_to_time(string)
|
103
|
-
return unless
|
89
|
+
return unless string.include?("-") # Time.new("1234") # => 1234-01-01 00:00:00
|
104
90
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
91
|
+
if is_utc?
|
92
|
+
::Time.new(string, in: "UTC")
|
93
|
+
else
|
94
|
+
::Time.new(string)
|
109
95
|
end
|
110
|
-
|
111
|
-
|
112
|
-
offset = \
|
113
|
-
if $8 == "Z"
|
114
|
-
0
|
115
|
-
else
|
116
|
-
offset_h, offset_m = $8.to_i, $9.to_i
|
117
|
-
offset_h.to_i * 3600 + (offset_h.negative? ? -1 : 1) * offset_m * 60
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
new_time($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, usec, offset)
|
96
|
+
rescue ArgumentError
|
97
|
+
nil
|
122
98
|
end
|
123
99
|
end
|
124
100
|
end
|
@@ -45,27 +45,6 @@ module ActiveModel
|
|
45
45
|
extend HelperMethods
|
46
46
|
include HelperMethods
|
47
47
|
|
48
|
-
##
|
49
|
-
# :method: validation_context
|
50
|
-
# Returns the context when running validations.
|
51
|
-
#
|
52
|
-
# This is useful when running validations except a certain context (opposite to the +on+ option).
|
53
|
-
#
|
54
|
-
# class Person
|
55
|
-
# include ActiveModel::Validations
|
56
|
-
#
|
57
|
-
# attr_accessor :name
|
58
|
-
# validates :name, presence: true, if: -> { validation_context != :custom }
|
59
|
-
# end
|
60
|
-
#
|
61
|
-
# person = Person.new
|
62
|
-
# person.valid? #=> false
|
63
|
-
# person.valid?(:new) #=> false
|
64
|
-
# person.valid?(:custom) #=> true
|
65
|
-
|
66
|
-
##
|
67
|
-
attr_accessor :validation_context
|
68
|
-
private :validation_context=
|
69
48
|
define_callbacks :validate, scope: :name
|
70
49
|
|
71
50
|
class_attribute :_validators, instance_writer: false, default: Hash.new { |h, k| h[k] = [] }
|
@@ -361,15 +340,23 @@ module ActiveModel
|
|
361
340
|
# person.valid? # => true
|
362
341
|
# person.valid?(:new) # => false
|
363
342
|
def valid?(context = nil)
|
364
|
-
current_context
|
343
|
+
current_context = validation_context
|
344
|
+
context_for_validation.context = context
|
365
345
|
errors.clear
|
366
346
|
run_validations!
|
367
347
|
ensure
|
368
|
-
|
348
|
+
context_for_validation.context = current_context
|
369
349
|
end
|
370
350
|
|
371
351
|
alias_method :validate, :valid?
|
372
352
|
|
353
|
+
def freeze
|
354
|
+
errors
|
355
|
+
context_for_validation
|
356
|
+
|
357
|
+
super
|
358
|
+
end
|
359
|
+
|
373
360
|
# Performs the opposite of <tt>valid?</tt>. Returns +true+ if errors were
|
374
361
|
# added, +false+ otherwise.
|
375
362
|
#
|
@@ -430,11 +417,38 @@ module ActiveModel
|
|
430
417
|
# end
|
431
418
|
alias :read_attribute_for_validation :send
|
432
419
|
|
420
|
+
# Returns the context when running validations.
|
421
|
+
#
|
422
|
+
# This is useful when running validations except a certain context (opposite to the +on+ option).
|
423
|
+
#
|
424
|
+
# class Person
|
425
|
+
# include ActiveModel::Validations
|
426
|
+
#
|
427
|
+
# attr_accessor :name
|
428
|
+
# validates :name, presence: true, if: -> { validation_context != :custom }
|
429
|
+
# end
|
430
|
+
#
|
431
|
+
# person = Person.new
|
432
|
+
# person.valid? #=> false
|
433
|
+
# person.valid?(:new) #=> false
|
434
|
+
# person.valid?(:custom) #=> true
|
435
|
+
def validation_context
|
436
|
+
context_for_validation.context
|
437
|
+
end
|
438
|
+
|
433
439
|
private
|
440
|
+
def validation_context=(context)
|
441
|
+
context_for_validation.context = context
|
442
|
+
end
|
443
|
+
|
444
|
+
def context_for_validation
|
445
|
+
@context_for_validation ||= ValidationContext.new
|
446
|
+
end
|
447
|
+
|
434
448
|
def init_internals
|
435
449
|
super
|
436
450
|
@errors = nil
|
437
|
-
@
|
451
|
+
@context_for_validation = nil
|
438
452
|
end
|
439
453
|
|
440
454
|
def run_validations!
|
@@ -466,6 +480,10 @@ module ActiveModel
|
|
466
480
|
super(I18n.t(:"#{@model.class.i18n_scope}.errors.messages.model_invalid", errors: errors, default: :"errors.messages.model_invalid"))
|
467
481
|
end
|
468
482
|
end
|
483
|
+
|
484
|
+
class ValidationContext # :nodoc:
|
485
|
+
attr_accessor :context
|
486
|
+
end
|
469
487
|
end
|
470
488
|
|
471
489
|
Dir[File.expand_path("validations/*.rb", __dir__)].each { |file| require file }
|
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:
|
4
|
+
version: 8.0.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-26 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:
|
19
|
+
version: 8.0.0.beta1
|
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:
|
26
|
+
version: 8.0.0.beta1
|
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.
|
@@ -112,10 +112,10 @@ licenses:
|
|
112
112
|
- MIT
|
113
113
|
metadata:
|
114
114
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
115
|
-
changelog_uri: https://github.com/rails/rails/blob/
|
116
|
-
documentation_uri: https://api.rubyonrails.org/
|
115
|
+
changelog_uri: https://github.com/rails/rails/blob/v8.0.0.beta1/activemodel/CHANGELOG.md
|
116
|
+
documentation_uri: https://api.rubyonrails.org/v8.0.0.beta1/
|
117
117
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
118
|
-
source_code_uri: https://github.com/rails/rails/tree/
|
118
|
+
source_code_uri: https://github.com/rails/rails/tree/v8.0.0.beta1/activemodel
|
119
119
|
rubygems_mfa_required: 'true'
|
120
120
|
post_install_message:
|
121
121
|
rdoc_options: []
|
@@ -125,7 +125,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
125
|
requirements:
|
126
126
|
- - ">="
|
127
127
|
- !ruby/object:Gem::Version
|
128
|
-
version: 3.
|
128
|
+
version: 3.2.0
|
129
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
130
|
requirements:
|
131
131
|
- - ">="
|