activemodel 7.0.3.1 → 6.1.7.1
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 +103 -84
- data/MIT-LICENSE +0 -1
- data/README.rdoc +3 -3
- data/lib/active_model/attribute.rb +0 -4
- data/lib/active_model/attribute_methods.rb +82 -67
- data/lib/active_model/attribute_set/builder.rb +10 -1
- data/lib/active_model/attribute_set.rb +1 -4
- data/lib/active_model/attributes.rb +12 -15
- data/lib/active_model/callbacks.rb +3 -3
- data/lib/active_model/conversion.rb +2 -2
- data/lib/active_model/dirty.rb +4 -5
- data/lib/active_model/error.rb +2 -2
- data/lib/active_model/errors.rb +248 -55
- data/lib/active_model/gem_version.rb +4 -4
- data/lib/active_model/locale/en.yml +0 -1
- data/lib/active_model/model.rb +59 -6
- data/lib/active_model/naming.rb +8 -15
- data/lib/active_model/secure_password.rb +1 -1
- data/lib/active_model/serialization.rb +2 -6
- data/lib/active_model/translation.rb +2 -2
- data/lib/active_model/type/date.rb +1 -1
- data/lib/active_model/type/helpers/numeric.rb +1 -9
- data/lib/active_model/type/helpers/time_value.rb +3 -3
- data/lib/active_model/type/integer.rb +1 -4
- data/lib/active_model/type/registry.rb +38 -8
- data/lib/active_model/type/time.rb +1 -1
- data/lib/active_model/type.rb +6 -6
- data/lib/active_model/validations/absence.rb +2 -2
- data/lib/active_model/validations/acceptance.rb +1 -1
- data/lib/active_model/validations/callbacks.rb +1 -1
- data/lib/active_model/validations/clusivity.rb +1 -1
- data/lib/active_model/validations/confirmation.rb +5 -5
- data/lib/active_model/validations/exclusion.rb +3 -3
- data/lib/active_model/validations/format.rb +1 -1
- data/lib/active_model/validations/inclusion.rb +3 -3
- data/lib/active_model/validations/length.rb +2 -2
- data/lib/active_model/validations/numericality.rb +22 -29
- data/lib/active_model/validations/presence.rb +1 -1
- data/lib/active_model/validations/validates.rb +3 -3
- data/lib/active_model/validations/with.rb +4 -4
- data/lib/active_model/validations.rb +12 -12
- data/lib/active_model/validator.rb +5 -5
- data/lib/active_model/version.rb +1 -1
- data/lib/active_model.rb +0 -1
- metadata +9 -12
- data/lib/active_model/api.rb +0 -99
- data/lib/active_model/validations/comparability.rb +0 -29
- data/lib/active_model/validations/comparison.rb +0 -82
@@ -4,26 +4,25 @@ require "active_model/attribute_set"
|
|
4
4
|
require "active_model/attribute/user_provided_default"
|
5
5
|
|
6
6
|
module ActiveModel
|
7
|
-
module Attributes
|
7
|
+
module Attributes #:nodoc:
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
include ActiveModel::AttributeMethods
|
10
10
|
|
11
11
|
included do
|
12
|
-
attribute_method_suffix "="
|
12
|
+
attribute_method_suffix "="
|
13
13
|
class_attribute :attribute_types, :_default_attributes, instance_accessor: false
|
14
14
|
self.attribute_types = Hash.new(Type.default_value)
|
15
15
|
self._default_attributes = AttributeSet.new({})
|
16
16
|
end
|
17
17
|
|
18
18
|
module ClassMethods
|
19
|
-
def attribute(name,
|
19
|
+
def attribute(name, type = Type::Value.new, **options)
|
20
20
|
name = name.to_s
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
define_default_attribute(name, default, cast_type)
|
21
|
+
if type.is_a?(Symbol)
|
22
|
+
type = ActiveModel::Type.lookup(type, **options.except(:default))
|
23
|
+
end
|
24
|
+
self.attribute_types = attribute_types.merge(name => type)
|
25
|
+
define_default_attribute(name, options.fetch(:default, NO_DEFAULT_PROVIDED), type)
|
27
26
|
define_attribute_method(name)
|
28
27
|
end
|
29
28
|
|
@@ -47,12 +46,10 @@ module ActiveModel
|
|
47
46
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
48
47
|
owner, name, writer: true,
|
49
48
|
) do |temp_method_name, attr_name_expr|
|
50
|
-
owner
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
"end"
|
55
|
-
end
|
49
|
+
owner <<
|
50
|
+
"def #{temp_method_name}(value)" <<
|
51
|
+
" _write_attribute(#{attr_name_expr}, value)" <<
|
52
|
+
"end"
|
56
53
|
end
|
57
54
|
end
|
58
55
|
|
@@ -32,7 +32,7 @@ module ActiveModel
|
|
32
32
|
# end
|
33
33
|
# end
|
34
34
|
#
|
35
|
-
# Then in your class, you can use the +before_create+, +after_create
|
35
|
+
# Then in your class, you can use the +before_create+, +after_create+ and
|
36
36
|
# +around_create+ methods, just as you would in an Active Record model.
|
37
37
|
#
|
38
38
|
# before_create :action_before_create
|
@@ -63,7 +63,7 @@ module ActiveModel
|
|
63
63
|
# NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
|
64
64
|
#
|
65
65
|
module Callbacks
|
66
|
-
def self.extended(base)
|
66
|
+
def self.extended(base) #:nodoc:
|
67
67
|
base.class_eval do
|
68
68
|
include ActiveSupport::Callbacks
|
69
69
|
end
|
@@ -84,7 +84,7 @@ module ActiveModel
|
|
84
84
|
# define_model_callbacks :update, only: :before
|
85
85
|
# define_model_callbacks :destroy, only: :around
|
86
86
|
#
|
87
|
-
# Would create +after_create+, +before_update
|
87
|
+
# Would create +after_create+, +before_update+ and +around_destroy+ methods
|
88
88
|
# only.
|
89
89
|
#
|
90
90
|
# You can pass in a class to before_<type>, after_<type> and around_<type>,
|
@@ -96,10 +96,10 @@ module ActiveModel
|
|
96
96
|
self.class._to_partial_path
|
97
97
|
end
|
98
98
|
|
99
|
-
module ClassMethods
|
99
|
+
module ClassMethods #:nodoc:
|
100
100
|
# Provide a class level cache for #to_partial_path. This is an
|
101
101
|
# internal method and should not be accessed directly.
|
102
|
-
def _to_partial_path
|
102
|
+
def _to_partial_path #:nodoc:
|
103
103
|
@_to_partial_path ||= begin
|
104
104
|
element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(name))
|
105
105
|
collection = ActiveSupport::Inflector.tableize(name)
|
data/lib/active_model/dirty.rb
CHANGED
@@ -123,11 +123,10 @@ module ActiveModel
|
|
123
123
|
include ActiveModel::AttributeMethods
|
124
124
|
|
125
125
|
included do
|
126
|
-
attribute_method_suffix "
|
127
|
-
attribute_method_suffix "
|
128
|
-
|
129
|
-
attribute_method_affix prefix: "
|
130
|
-
attribute_method_affix prefix: "clear_", suffix: "_change", parameters: false
|
126
|
+
attribute_method_suffix "_changed?", "_change", "_will_change!", "_was"
|
127
|
+
attribute_method_suffix "_previously_changed?", "_previous_change", "_previously_was"
|
128
|
+
attribute_method_affix prefix: "restore_", suffix: "!"
|
129
|
+
attribute_method_affix prefix: "clear_", suffix: "_change"
|
131
130
|
end
|
132
131
|
|
133
132
|
def initialize_dup(other) # :nodoc:
|
data/lib/active_model/error.rb
CHANGED
@@ -159,7 +159,7 @@ module ActiveModel
|
|
159
159
|
self.class.full_message(attribute, message, @base)
|
160
160
|
end
|
161
161
|
|
162
|
-
# See if error matches provided +attribute+, +type
|
162
|
+
# See if error matches provided +attribute+, +type+ and +options+.
|
163
163
|
#
|
164
164
|
# Omitted params are not checked for a match.
|
165
165
|
def match?(attribute, type = nil, **options)
|
@@ -176,7 +176,7 @@ module ActiveModel
|
|
176
176
|
true
|
177
177
|
end
|
178
178
|
|
179
|
-
# See if error matches provided +attribute+, +type
|
179
|
+
# See if error matches provided +attribute+, +type+ and +options+ exactly.
|
180
180
|
#
|
181
181
|
# All params must be equal to Error's own attributes to be considered a
|
182
182
|
# strict match.
|
data/lib/active_model/errors.rb
CHANGED
@@ -48,9 +48,9 @@ module ActiveModel
|
|
48
48
|
#
|
49
49
|
# The last three methods are required in your object for +Errors+ to be
|
50
50
|
# able to generate error messages correctly and also handle multiple
|
51
|
-
# languages. Of course, if you extend your object with ActiveModel::Translation
|
51
|
+
# languages. Of course, if you extend your object with <tt>ActiveModel::Translation</tt>
|
52
52
|
# you will not need to implement the last two. Likewise, using
|
53
|
-
# ActiveModel::Validations will handle the validation related methods
|
53
|
+
# <tt>ActiveModel::Validations</tt> will handle the validation related methods
|
54
54
|
# for you.
|
55
55
|
#
|
56
56
|
# The above allows you to do:
|
@@ -63,19 +63,12 @@ module ActiveModel
|
|
63
63
|
include Enumerable
|
64
64
|
|
65
65
|
extend Forwardable
|
66
|
+
def_delegators :@errors, :size, :clear, :blank?, :empty?, :uniq!, :any?
|
67
|
+
# TODO: forward all enumerable methods after `each` deprecation is removed.
|
68
|
+
def_delegators :@errors, :count
|
66
69
|
|
67
|
-
|
68
|
-
|
69
|
-
# :call-seq: each(&block)
|
70
|
-
#
|
71
|
-
# Iterates through each error object.
|
72
|
-
#
|
73
|
-
# person.errors.add(:name, :too_short, count: 2)
|
74
|
-
# person.errors.each do |error|
|
75
|
-
# # Will yield <#ActiveModel::Error attribute=name, type=too_short,
|
76
|
-
# options={:count=>3}>
|
77
|
-
# end
|
78
|
-
def_delegators :@errors, :each, :clear, :empty?, :size, :uniq!
|
70
|
+
LEGACY_ATTRIBUTES = [:messages, :details].freeze
|
71
|
+
private_constant :LEGACY_ATTRIBUTES
|
79
72
|
|
80
73
|
# The actual array of +Error+ objects
|
81
74
|
# This method is aliased to <tt>objects</tt>.
|
@@ -102,14 +95,11 @@ module ActiveModel
|
|
102
95
|
# Copies the errors from <tt>other</tt>.
|
103
96
|
# For copying errors but keep <tt>@base</tt> as is.
|
104
97
|
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
# * +other+ - The ActiveModel::Errors instance.
|
98
|
+
# other - The ActiveModel::Errors instance.
|
108
99
|
#
|
109
|
-
#
|
100
|
+
# Examples
|
110
101
|
#
|
111
102
|
# person.errors.copy!(other)
|
112
|
-
#
|
113
103
|
def copy!(other) # :nodoc:
|
114
104
|
@errors = other.errors.deep_dup
|
115
105
|
@errors.each { |error|
|
@@ -117,15 +107,14 @@ module ActiveModel
|
|
117
107
|
}
|
118
108
|
end
|
119
109
|
|
120
|
-
# Imports one error
|
110
|
+
# Imports one error
|
121
111
|
# Imported errors are wrapped as a NestedError,
|
122
112
|
# providing access to original error object.
|
123
113
|
# If attribute or type needs to be overridden, use +override_options+.
|
124
114
|
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
# * +:type+ - Override type of the error.
|
115
|
+
# override_options - Hash
|
116
|
+
# @option override_options [Symbol] :attribute Override the attribute the error belongs to
|
117
|
+
# @option override_options [Symbol] :type Override type of the error.
|
129
118
|
def import(error, override_options = {})
|
130
119
|
[:attribute, :type].each do |key|
|
131
120
|
if override_options.key?(key)
|
@@ -136,25 +125,39 @@ module ActiveModel
|
|
136
125
|
end
|
137
126
|
|
138
127
|
# Merges the errors from <tt>other</tt>,
|
139
|
-
# each Error wrapped as NestedError
|
140
|
-
#
|
141
|
-
# ==== Parameters
|
128
|
+
# each <tt>Error</tt> wrapped as <tt>NestedError</tt>.
|
142
129
|
#
|
143
|
-
#
|
130
|
+
# other - The ActiveModel::Errors instance.
|
144
131
|
#
|
145
|
-
#
|
132
|
+
# Examples
|
146
133
|
#
|
147
134
|
# person.errors.merge!(other)
|
148
|
-
#
|
149
135
|
def merge!(other)
|
150
|
-
return errors if equal?(other)
|
151
|
-
|
152
136
|
other.errors.each { |error|
|
153
137
|
import(error)
|
154
138
|
}
|
155
139
|
end
|
156
140
|
|
157
|
-
#
|
141
|
+
# Removes all errors except the given keys. Returns a hash containing the removed errors.
|
142
|
+
#
|
143
|
+
# person.errors.keys # => [:name, :age, :gender, :city]
|
144
|
+
# person.errors.slice!(:age, :gender) # => { :name=>["cannot be nil"], :city=>["cannot be nil"] }
|
145
|
+
# person.errors.keys # => [:age, :gender]
|
146
|
+
def slice!(*keys)
|
147
|
+
deprecation_removal_warning(:slice!)
|
148
|
+
|
149
|
+
keys = keys.map(&:to_sym)
|
150
|
+
|
151
|
+
results = messages.dup.slice!(*keys)
|
152
|
+
|
153
|
+
@errors.keep_if do |error|
|
154
|
+
keys.include?(error.attribute)
|
155
|
+
end
|
156
|
+
|
157
|
+
results
|
158
|
+
end
|
159
|
+
|
160
|
+
# Search for errors matching +attribute+, +type+ or +options+.
|
158
161
|
#
|
159
162
|
# Only supplied params will be matched.
|
160
163
|
#
|
@@ -202,7 +205,76 @@ module ActiveModel
|
|
202
205
|
# person.errors[:name] # => ["cannot be nil"]
|
203
206
|
# person.errors['name'] # => ["cannot be nil"]
|
204
207
|
def [](attribute)
|
205
|
-
messages_for(attribute)
|
208
|
+
DeprecationHandlingMessageArray.new(messages_for(attribute), self, attribute)
|
209
|
+
end
|
210
|
+
|
211
|
+
# Iterates through each error object.
|
212
|
+
#
|
213
|
+
# person.errors.add(:name, :too_short, count: 2)
|
214
|
+
# person.errors.each do |error|
|
215
|
+
# # Will yield <#ActiveModel::Error attribute=name, type=too_short,
|
216
|
+
# options={:count=>3}>
|
217
|
+
# end
|
218
|
+
#
|
219
|
+
# To be backward compatible with past deprecated hash-like behavior,
|
220
|
+
# when block accepts two parameters instead of one, it
|
221
|
+
# iterates through each error key, value pair in the error messages hash.
|
222
|
+
# Yields the attribute and the error for that attribute. If the attribute
|
223
|
+
# has more than one error message, yields once for each error message.
|
224
|
+
#
|
225
|
+
# person.errors.add(:name, :blank, message: "can't be blank")
|
226
|
+
# person.errors.each do |attribute, message|
|
227
|
+
# # Will yield :name and "can't be blank"
|
228
|
+
# end
|
229
|
+
#
|
230
|
+
# person.errors.add(:name, :not_specified, message: "must be specified")
|
231
|
+
# person.errors.each do |attribute, message|
|
232
|
+
# # Will yield :name and "can't be blank"
|
233
|
+
# # then yield :name and "must be specified"
|
234
|
+
# end
|
235
|
+
def each(&block)
|
236
|
+
if block.arity <= 1
|
237
|
+
@errors.each(&block)
|
238
|
+
else
|
239
|
+
ActiveSupport::Deprecation.warn(<<~MSG)
|
240
|
+
Enumerating ActiveModel::Errors as a hash has been deprecated.
|
241
|
+
In Rails 6.1, `errors` is an array of Error objects,
|
242
|
+
therefore it should be accessed by a block with a single block
|
243
|
+
parameter like this:
|
244
|
+
|
245
|
+
person.errors.each do |error|
|
246
|
+
attribute = error.attribute
|
247
|
+
message = error.message
|
248
|
+
end
|
249
|
+
|
250
|
+
You are passing a block expecting two parameters,
|
251
|
+
so the old hash behavior is simulated. As this is deprecated,
|
252
|
+
this will result in an ArgumentError in Rails 7.0.
|
253
|
+
MSG
|
254
|
+
@errors.
|
255
|
+
sort { |a, b| a.attribute <=> b.attribute }.
|
256
|
+
each { |error| yield error.attribute, error.message }
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Returns all message values.
|
261
|
+
#
|
262
|
+
# person.errors.messages # => {:name=>["cannot be nil", "must be specified"]}
|
263
|
+
# person.errors.values # => [["cannot be nil", "must be specified"]]
|
264
|
+
def values
|
265
|
+
deprecation_removal_warning(:values, "errors.map { |error| error.message }")
|
266
|
+
@errors.map(&:message).freeze
|
267
|
+
end
|
268
|
+
|
269
|
+
# Returns all message keys.
|
270
|
+
#
|
271
|
+
# person.errors.messages # => {:name=>["cannot be nil", "must be specified"]}
|
272
|
+
# person.errors.keys # => [:name]
|
273
|
+
def keys
|
274
|
+
deprecation_removal_warning(:keys, "errors.attribute_names")
|
275
|
+
keys = @errors.map(&:attribute)
|
276
|
+
keys.uniq!
|
277
|
+
keys.freeze
|
206
278
|
end
|
207
279
|
|
208
280
|
# Returns all error attribute names
|
@@ -213,6 +285,22 @@ module ActiveModel
|
|
213
285
|
@errors.map(&:attribute).uniq.freeze
|
214
286
|
end
|
215
287
|
|
288
|
+
# Returns an xml formatted representation of the Errors hash.
|
289
|
+
#
|
290
|
+
# person.errors.add(:name, :blank, message: "can't be blank")
|
291
|
+
# person.errors.add(:name, :not_specified, message: "must be specified")
|
292
|
+
# person.errors.to_xml
|
293
|
+
# # =>
|
294
|
+
# # <?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
295
|
+
# # <errors>
|
296
|
+
# # <error>name can't be blank</error>
|
297
|
+
# # <error>name must be specified</error>
|
298
|
+
# # </errors>
|
299
|
+
def to_xml(options = {})
|
300
|
+
deprecation_removal_warning(:to_xml)
|
301
|
+
to_a.to_xml({ root: "errors", skip_types: true }.merge!(options))
|
302
|
+
end
|
303
|
+
|
216
304
|
# Returns a Hash that can be used as the JSON representation for this
|
217
305
|
# object. You can pass the <tt>:full_messages</tt> option. This determines
|
218
306
|
# if the json object should contain full messages or not (false by default).
|
@@ -235,26 +323,33 @@ module ActiveModel
|
|
235
323
|
end
|
236
324
|
end
|
237
325
|
|
238
|
-
|
326
|
+
def to_h
|
327
|
+
ActiveSupport::Deprecation.warn(<<~EOM)
|
328
|
+
ActiveModel::Errors#to_h is deprecated and will be removed in Rails 7.0.
|
329
|
+
Please use `ActiveModel::Errors.to_hash` instead. The values in the hash
|
330
|
+
returned by `ActiveModel::Errors.to_hash` is an array of error messages.
|
331
|
+
EOM
|
239
332
|
|
240
|
-
|
333
|
+
to_hash.transform_values { |values| values.last }
|
334
|
+
end
|
241
335
|
|
242
336
|
# Returns a Hash of attributes with an array of their error messages.
|
337
|
+
#
|
338
|
+
# Updating this hash would still update errors state for backward
|
339
|
+
# compatibility, but this behavior is deprecated.
|
243
340
|
def messages
|
244
|
-
|
245
|
-
hash.default = EMPTY_ARRAY
|
246
|
-
hash.freeze
|
247
|
-
hash
|
341
|
+
DeprecationHandlingMessageHash.new(self)
|
248
342
|
end
|
249
343
|
|
250
344
|
# Returns a Hash of attributes with an array of their error details.
|
345
|
+
#
|
346
|
+
# Updating this hash would still update errors state for backward
|
347
|
+
# compatibility, but this behavior is deprecated.
|
251
348
|
def details
|
252
349
|
hash = group_by_attribute.transform_values do |errors|
|
253
350
|
errors.map(&:details)
|
254
351
|
end
|
255
|
-
hash
|
256
|
-
hash.freeze
|
257
|
-
hash
|
352
|
+
DeprecationHandlingDetailsHash.new(hash)
|
258
353
|
end
|
259
354
|
|
260
355
|
# Returns a Hash of attributes with an array of their Error objects.
|
@@ -283,14 +378,6 @@ module ActiveModel
|
|
283
378
|
# If +type+ is a symbol, it will be translated using the appropriate
|
284
379
|
# scope (see +generate_message+).
|
285
380
|
#
|
286
|
-
# person.errors.add(:name, :blank)
|
287
|
-
# person.errors.messages
|
288
|
-
# # => {:name=>["can't be blank"]}
|
289
|
-
#
|
290
|
-
# person.errors.add(:name, :too_long, { count: 25 })
|
291
|
-
# person.errors.messages
|
292
|
-
# # => ["is too long (maximum is 25 characters)"]
|
293
|
-
#
|
294
381
|
# If +type+ is a proc, it will be called, allowing for things like
|
295
382
|
# <tt>Time.now</tt> to be used within an error.
|
296
383
|
#
|
@@ -434,7 +521,7 @@ module ActiveModel
|
|
434
521
|
# if it's not there, it's looked up in <tt>activemodel.errors.models.MODEL.MESSAGE</tt> and if
|
435
522
|
# that is not there also, it returns the translation of the default message
|
436
523
|
# (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model
|
437
|
-
# name, translated attribute name
|
524
|
+
# name, translated attribute name and the value are available for
|
438
525
|
# interpolation.
|
439
526
|
#
|
440
527
|
# When using inheritance in your models, it will check all the inherited
|
@@ -455,10 +542,25 @@ module ActiveModel
|
|
455
542
|
Error.generate_message(attribute, type, @base, options)
|
456
543
|
end
|
457
544
|
|
458
|
-
def
|
459
|
-
|
545
|
+
def marshal_load(array) # :nodoc:
|
546
|
+
# Rails 5
|
547
|
+
@errors = []
|
548
|
+
@base = array[0]
|
549
|
+
add_from_legacy_details_hash(array[2])
|
550
|
+
end
|
551
|
+
|
552
|
+
def init_with(coder) # :nodoc:
|
553
|
+
data = coder.map
|
554
|
+
|
555
|
+
data.each { |k, v|
|
556
|
+
next if LEGACY_ATTRIBUTES.include?(k.to_sym)
|
557
|
+
instance_variable_set(:"@#{k}", v)
|
558
|
+
}
|
559
|
+
|
560
|
+
@errors ||= []
|
460
561
|
|
461
|
-
|
562
|
+
# Legacy support Rails 5.x details hash
|
563
|
+
add_from_legacy_details_hash(data["details"]) if data.key?("details")
|
462
564
|
end
|
463
565
|
|
464
566
|
private
|
@@ -470,6 +572,97 @@ module ActiveModel
|
|
470
572
|
|
471
573
|
[attribute.to_sym, type, options]
|
472
574
|
end
|
575
|
+
|
576
|
+
def add_from_legacy_details_hash(details)
|
577
|
+
details.each { |attribute, errors|
|
578
|
+
errors.each { |error|
|
579
|
+
type = error.delete(:error)
|
580
|
+
add(attribute, type, **error)
|
581
|
+
}
|
582
|
+
}
|
583
|
+
end
|
584
|
+
|
585
|
+
def deprecation_removal_warning(method_name, alternative_message = nil)
|
586
|
+
message = +"ActiveModel::Errors##{method_name} is deprecated and will be removed in Rails 7.0."
|
587
|
+
if alternative_message
|
588
|
+
message << "\n\nTo achieve the same use:\n\n "
|
589
|
+
message << alternative_message
|
590
|
+
end
|
591
|
+
ActiveSupport::Deprecation.warn(message)
|
592
|
+
end
|
593
|
+
|
594
|
+
def deprecation_rename_warning(old_method_name, new_method_name)
|
595
|
+
ActiveSupport::Deprecation.warn("ActiveModel::Errors##{old_method_name} is deprecated. Please call ##{new_method_name} instead.")
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
class DeprecationHandlingMessageHash < SimpleDelegator
|
600
|
+
def initialize(errors)
|
601
|
+
@errors = errors
|
602
|
+
super(prepare_content)
|
603
|
+
end
|
604
|
+
|
605
|
+
def []=(attribute, value)
|
606
|
+
ActiveSupport::Deprecation.warn("Calling `[]=` to an ActiveModel::Errors is deprecated. Please call `ActiveModel::Errors#add` instead.")
|
607
|
+
|
608
|
+
@errors.delete(attribute)
|
609
|
+
Array(value).each do |message|
|
610
|
+
@errors.add(attribute, message)
|
611
|
+
end
|
612
|
+
|
613
|
+
__setobj__ prepare_content
|
614
|
+
end
|
615
|
+
|
616
|
+
def delete(attribute)
|
617
|
+
ActiveSupport::Deprecation.warn("Calling `delete` to an ActiveModel::Errors messages hash is deprecated. Please call `ActiveModel::Errors#delete` instead.")
|
618
|
+
|
619
|
+
@errors.delete(attribute)
|
620
|
+
end
|
621
|
+
|
622
|
+
private
|
623
|
+
def prepare_content
|
624
|
+
content = @errors.to_hash
|
625
|
+
content.each do |attribute, value|
|
626
|
+
content[attribute] = DeprecationHandlingMessageArray.new(value, @errors, attribute)
|
627
|
+
end
|
628
|
+
content.default_proc = proc do |hash, attribute|
|
629
|
+
hash = hash.dup
|
630
|
+
hash[attribute] = DeprecationHandlingMessageArray.new([], @errors, attribute)
|
631
|
+
__setobj__ hash.freeze
|
632
|
+
hash[attribute]
|
633
|
+
end
|
634
|
+
content.freeze
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
class DeprecationHandlingMessageArray < SimpleDelegator
|
639
|
+
def initialize(content, errors, attribute)
|
640
|
+
@errors = errors
|
641
|
+
@attribute = attribute
|
642
|
+
super(content.freeze)
|
643
|
+
end
|
644
|
+
|
645
|
+
def <<(message)
|
646
|
+
ActiveSupport::Deprecation.warn("Calling `<<` to an ActiveModel::Errors message array in order to add an error is deprecated. Please call `ActiveModel::Errors#add` instead.")
|
647
|
+
|
648
|
+
@errors.add(@attribute, message)
|
649
|
+
__setobj__ @errors.messages_for(@attribute)
|
650
|
+
self
|
651
|
+
end
|
652
|
+
|
653
|
+
def clear
|
654
|
+
ActiveSupport::Deprecation.warn("Calling `clear` to an ActiveModel::Errors message array in order to delete all errors is deprecated. Please call `ActiveModel::Errors#delete` instead.")
|
655
|
+
|
656
|
+
@errors.delete(@attribute)
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
class DeprecationHandlingDetailsHash < SimpleDelegator
|
661
|
+
def initialize(details)
|
662
|
+
details.default = []
|
663
|
+
details.freeze
|
664
|
+
super(details)
|
665
|
+
end
|
473
666
|
end
|
474
667
|
|
475
668
|
# Raised when a validation cannot be corrected by end users and are considered
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveModel
|
4
|
-
# Returns the currently loaded
|
4
|
+
# Returns the version of the currently loaded \Active \Model as a <tt>Gem::Version</tt>
|
5
5
|
def self.gem_version
|
6
6
|
Gem::Version.new VERSION::STRING
|
7
7
|
end
|
8
8
|
|
9
9
|
module VERSION
|
10
|
-
MAJOR =
|
11
|
-
MINOR =
|
12
|
-
TINY =
|
10
|
+
MAJOR = 6
|
11
|
+
MINOR = 1
|
12
|
+
TINY = 7
|
13
13
|
PRE = "1"
|
14
14
|
|
15
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
data/lib/active_model/model.rb
CHANGED
@@ -3,10 +3,11 @@
|
|
3
3
|
module ActiveModel
|
4
4
|
# == Active \Model \Basic \Model
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# Includes the required interface for an object to interact with
|
7
|
+
# Action Pack and Action View, using different Active Model modules.
|
8
|
+
# It includes model name introspections, conversions, translations and
|
9
|
+
# validations. Besides that, it allows you to initialize the object with a
|
10
|
+
# hash of attributes, pretty much like Active Record does.
|
10
11
|
#
|
11
12
|
# A minimal implementation could be:
|
12
13
|
#
|
@@ -19,7 +20,23 @@ module ActiveModel
|
|
19
20
|
# person.name # => "bob"
|
20
21
|
# person.age # => "18"
|
21
22
|
#
|
22
|
-
#
|
23
|
+
# Note that, by default, <tt>ActiveModel::Model</tt> implements <tt>persisted?</tt>
|
24
|
+
# to return +false+, which is the most common case. You may want to override
|
25
|
+
# it in your class to simulate a different scenario:
|
26
|
+
#
|
27
|
+
# class Person
|
28
|
+
# include ActiveModel::Model
|
29
|
+
# attr_accessor :id, :name
|
30
|
+
#
|
31
|
+
# def persisted?
|
32
|
+
# self.id == 1
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# person = Person.new(id: 1, name: 'bob')
|
37
|
+
# person.persisted? # => true
|
38
|
+
#
|
39
|
+
# Also, if for some reason you need to run code on <tt>initialize</tt>, make
|
23
40
|
# sure you call +super+ if you want the attributes hash initialization to
|
24
41
|
# happen.
|
25
42
|
#
|
@@ -41,6 +58,42 @@ module ActiveModel
|
|
41
58
|
# (see below).
|
42
59
|
module Model
|
43
60
|
extend ActiveSupport::Concern
|
44
|
-
include ActiveModel::
|
61
|
+
include ActiveModel::AttributeAssignment
|
62
|
+
include ActiveModel::Validations
|
63
|
+
include ActiveModel::Conversion
|
64
|
+
|
65
|
+
included do
|
66
|
+
extend ActiveModel::Naming
|
67
|
+
extend ActiveModel::Translation
|
68
|
+
end
|
69
|
+
|
70
|
+
# Initializes a new model with the given +params+.
|
71
|
+
#
|
72
|
+
# class Person
|
73
|
+
# include ActiveModel::Model
|
74
|
+
# attr_accessor :name, :age
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# person = Person.new(name: 'bob', age: '18')
|
78
|
+
# person.name # => "bob"
|
79
|
+
# person.age # => "18"
|
80
|
+
def initialize(attributes = {})
|
81
|
+
assign_attributes(attributes) if attributes
|
82
|
+
|
83
|
+
super()
|
84
|
+
end
|
85
|
+
|
86
|
+
# Indicates if the model is persisted. Default is +false+.
|
87
|
+
#
|
88
|
+
# class Person
|
89
|
+
# include ActiveModel::Model
|
90
|
+
# attr_accessor :id, :name
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# person = Person.new(id: 1, name: 'bob')
|
94
|
+
# person.persisted? # => false
|
95
|
+
def persisted?
|
96
|
+
false
|
97
|
+
end
|
45
98
|
end
|
46
99
|
end
|