activemodel 7.0.4 → 6.1.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +101 -103
- 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 +5 -5
- 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 +2 -25
- 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,16 +1,16 @@
|
|
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 =
|
13
|
-
PRE =
|
10
|
+
MAJOR = 6
|
11
|
+
MINOR = 1
|
12
|
+
TINY = 7
|
13
|
+
PRE = "1"
|
14
14
|
|
15
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
16
16
|
end
|
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
|