activemodel 7.0.5 → 7.1.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +158 -123
- data/MIT-LICENSE +1 -1
- data/README.rdoc +11 -11
- data/lib/active_model/access.rb +16 -0
- data/lib/active_model/api.rb +5 -5
- data/lib/active_model/attribute/user_provided_default.rb +4 -0
- data/lib/active_model/attribute.rb +26 -1
- data/lib/active_model/attribute_assignment.rb +1 -1
- data/lib/active_model/attribute_methods.rb +103 -64
- data/lib/active_model/attribute_registration.rb +77 -0
- data/lib/active_model/attribute_set.rb +10 -1
- data/lib/active_model/attributes.rb +62 -45
- data/lib/active_model/callbacks.rb +5 -5
- data/lib/active_model/conversion.rb +14 -4
- data/lib/active_model/deprecator.rb +7 -0
- data/lib/active_model/dirty.rb +134 -13
- data/lib/active_model/error.rb +5 -4
- data/lib/active_model/errors.rb +37 -6
- data/lib/active_model/forbidden_attributes_protection.rb +2 -0
- data/lib/active_model/gem_version.rb +4 -4
- data/lib/active_model/lint.rb +1 -1
- data/lib/active_model/locale/en.yml +1 -0
- data/lib/active_model/model.rb +34 -2
- data/lib/active_model/naming.rb +29 -10
- data/lib/active_model/railtie.rb +4 -0
- data/lib/active_model/secure_password.rb +61 -23
- data/lib/active_model/serialization.rb +3 -3
- data/lib/active_model/serializers/json.rb +1 -1
- data/lib/active_model/translation.rb +18 -16
- data/lib/active_model/type/big_integer.rb +23 -1
- data/lib/active_model/type/binary.rb +10 -2
- data/lib/active_model/type/boolean.rb +11 -9
- data/lib/active_model/type/date.rb +28 -2
- data/lib/active_model/type/date_time.rb +45 -3
- data/lib/active_model/type/decimal.rb +39 -1
- data/lib/active_model/type/float.rb +30 -1
- data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +5 -1
- data/lib/active_model/type/helpers/mutable.rb +4 -4
- data/lib/active_model/type/helpers/numeric.rb +6 -1
- data/lib/active_model/type/helpers/time_value.rb +28 -12
- data/lib/active_model/type/immutable_string.rb +37 -1
- data/lib/active_model/type/integer.rb +44 -1
- data/lib/active_model/type/serialize_cast_value.rb +47 -0
- data/lib/active_model/type/string.rb +9 -1
- data/lib/active_model/type/time.rb +48 -7
- data/lib/active_model/type/value.rb +23 -3
- data/lib/active_model/type.rb +1 -0
- data/lib/active_model/validations/absence.rb +1 -1
- data/lib/active_model/validations/acceptance.rb +1 -1
- data/lib/active_model/validations/callbacks.rb +4 -4
- data/lib/active_model/validations/clusivity.rb +5 -8
- data/lib/active_model/validations/comparability.rb +0 -11
- data/lib/active_model/validations/comparison.rb +15 -7
- data/lib/active_model/validations/format.rb +6 -7
- data/lib/active_model/validations/length.rb +10 -8
- data/lib/active_model/validations/numericality.rb +35 -23
- data/lib/active_model/validations/presence.rb +1 -1
- data/lib/active_model/validations/resolve_value.rb +26 -0
- data/lib/active_model/validations/validates.rb +4 -4
- data/lib/active_model/validations/with.rb +9 -2
- data/lib/active_model/validations.rb +44 -9
- data/lib/active_model/validator.rb +7 -5
- data/lib/active_model/version.rb +1 -1
- data/lib/active_model.rb +5 -1
- metadata +16 -11
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveModel
|
4
|
-
#
|
4
|
+
# = Active \Model \Conversion
|
5
5
|
#
|
6
6
|
# Handles default conversions: to_model, to_key, to_param, and to_partial_path.
|
7
7
|
#
|
@@ -24,6 +24,14 @@ module ActiveModel
|
|
24
24
|
module Conversion
|
25
25
|
extend ActiveSupport::Concern
|
26
26
|
|
27
|
+
included do
|
28
|
+
##
|
29
|
+
# :singleton-method:
|
30
|
+
#
|
31
|
+
# Accepts a string that will be used as a delimiter of object's key values in the `to_param` method.
|
32
|
+
class_attribute :param_delimiter, instance_reader: false, default: "-"
|
33
|
+
end
|
34
|
+
|
27
35
|
# If your object is already designed to implement all of the \Active \Model
|
28
36
|
# you can use the default <tt>:to_model</tt> implementation, which simply
|
29
37
|
# returns +self+.
|
@@ -58,7 +66,7 @@ module ActiveModel
|
|
58
66
|
# person.to_key # => [1]
|
59
67
|
def to_key
|
60
68
|
key = respond_to?(:id) && id
|
61
|
-
key ?
|
69
|
+
key ? Array(key) : nil
|
62
70
|
end
|
63
71
|
|
64
72
|
# Returns a +string+ representing the object's key suitable for use in URLs,
|
@@ -80,7 +88,7 @@ module ActiveModel
|
|
80
88
|
# person = Person.new(1)
|
81
89
|
# person.to_param # => "1"
|
82
90
|
def to_param
|
83
|
-
(persisted? && key = to_key) ? key.join(
|
91
|
+
(persisted? && (key = to_key) && key.all?) ? key.join(self.class.param_delimiter) : nil
|
84
92
|
end
|
85
93
|
|
86
94
|
# Returns a +string+ identifying the path associated with the object.
|
@@ -100,7 +108,9 @@ module ActiveModel
|
|
100
108
|
# Provide a class level cache for #to_partial_path. This is an
|
101
109
|
# internal method and should not be accessed directly.
|
102
110
|
def _to_partial_path # :nodoc:
|
103
|
-
@_to_partial_path ||=
|
111
|
+
@_to_partial_path ||= if respond_to?(:model_name)
|
112
|
+
"#{model_name.collection}/#{model_name.element}"
|
113
|
+
else
|
104
114
|
element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(name))
|
105
115
|
collection = ActiveSupport::Inflector.tableize(name)
|
106
116
|
"#{collection}/#{element}"
|
data/lib/active_model/dirty.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_model/attribute_mutation_tracker"
|
4
4
|
|
5
5
|
module ActiveModel
|
6
|
-
#
|
6
|
+
# = Active \Model \Dirty
|
7
7
|
#
|
8
8
|
# Provides a way to track changes in your object in the same way as
|
9
9
|
# Active Record does.
|
@@ -13,8 +13,7 @@ module ActiveModel
|
|
13
13
|
# * <tt>include ActiveModel::Dirty</tt> in your object.
|
14
14
|
# * Call <tt>define_attribute_methods</tt> passing each method you want to
|
15
15
|
# track.
|
16
|
-
# * Call <tt
|
17
|
-
# attribute.
|
16
|
+
# * Call <tt>*_will_change!</tt> before each change to the tracked attribute.
|
18
17
|
# * Call <tt>changes_applied</tt> after the changes are persisted.
|
19
18
|
# * Call <tt>clear_changes_information</tt> when you want to reset the changes
|
20
19
|
# information.
|
@@ -109,20 +108,136 @@ module ActiveModel
|
|
109
108
|
# person.changes # => {"name" => ["Bill", "Bob"]}
|
110
109
|
#
|
111
110
|
# If an attribute is modified in-place then make use of
|
112
|
-
#
|
111
|
+
# {*_will_change!}[rdoc-label:method-i-2A_will_change-21] to mark that the attribute is changing.
|
113
112
|
# Otherwise \Active \Model can't track changes to in-place attributes. Note
|
114
113
|
# that Active Record can detect in-place modifications automatically. You do
|
115
|
-
# not need to call <tt
|
114
|
+
# not need to call <tt>*_will_change!</tt> on Active Record models.
|
116
115
|
#
|
117
116
|
# person.name_will_change!
|
118
117
|
# person.name_change # => ["Bill", "Bill"]
|
119
118
|
# person.name << 'y'
|
120
119
|
# person.name_change # => ["Bill", "Billy"]
|
120
|
+
#
|
121
|
+
# Methods can be invoked as +name_changed?+ or by passing an argument to the
|
122
|
+
# generic method <tt>attribute_changed?("name")</tt>.
|
121
123
|
module Dirty
|
122
124
|
extend ActiveSupport::Concern
|
123
125
|
include ActiveModel::AttributeMethods
|
124
126
|
|
125
127
|
included do
|
128
|
+
##
|
129
|
+
# :method: *_previously_changed?
|
130
|
+
#
|
131
|
+
# :call-seq: *_previously_changed?(**options)
|
132
|
+
#
|
133
|
+
# This method is generated for each attribute.
|
134
|
+
#
|
135
|
+
# Returns true if the attribute previously had unsaved changes.
|
136
|
+
#
|
137
|
+
# person = Person.new
|
138
|
+
# person.name = 'Britanny'
|
139
|
+
# person.save
|
140
|
+
# person.name_previously_changed? # => true
|
141
|
+
# person.name_previously_changed?(from: nil, to: 'Britanny') # => true
|
142
|
+
|
143
|
+
##
|
144
|
+
# :method: *_changed?
|
145
|
+
#
|
146
|
+
# This method is generated for each attribute.
|
147
|
+
#
|
148
|
+
# Returns true if the attribute has unsaved changes.
|
149
|
+
#
|
150
|
+
# person = Person.new
|
151
|
+
# person.name = 'Andrew'
|
152
|
+
# person.name_changed? # => true
|
153
|
+
|
154
|
+
##
|
155
|
+
# :method: *_change
|
156
|
+
#
|
157
|
+
# This method is generated for each attribute.
|
158
|
+
#
|
159
|
+
# Returns the old and the new value of the attribute.
|
160
|
+
#
|
161
|
+
# person = Person.new
|
162
|
+
# person.name = 'Nick'
|
163
|
+
# person.name_change # => [nil, 'Nick']
|
164
|
+
|
165
|
+
##
|
166
|
+
# :method: *_will_change!
|
167
|
+
#
|
168
|
+
# This method is generated for each attribute.
|
169
|
+
#
|
170
|
+
# If an attribute is modified in-place then make use of
|
171
|
+
# <tt>*_will_change!</tt> to mark that the attribute is changing.
|
172
|
+
# Otherwise Active Model can’t track changes to in-place attributes. Note
|
173
|
+
# that Active Record can detect in-place modifications automatically. You
|
174
|
+
# do not need to call <tt>*_will_change!</tt> on Active Record
|
175
|
+
# models.
|
176
|
+
#
|
177
|
+
# person = Person.new('Sandy')
|
178
|
+
# person.name_will_change!
|
179
|
+
# person.name_change # => ['Sandy', 'Sandy']
|
180
|
+
|
181
|
+
##
|
182
|
+
# :method: *_was
|
183
|
+
#
|
184
|
+
# This method is generated for each attribute.
|
185
|
+
#
|
186
|
+
# Returns the old value of the attribute.
|
187
|
+
#
|
188
|
+
# person = Person.new(name: 'Steph')
|
189
|
+
# person.name = 'Stephanie'
|
190
|
+
# person.name_was # => 'Steph'
|
191
|
+
|
192
|
+
##
|
193
|
+
# :method: *_previous_change
|
194
|
+
#
|
195
|
+
# This method is generated for each attribute.
|
196
|
+
#
|
197
|
+
# Returns the old and the new value of the attribute before the last save.
|
198
|
+
#
|
199
|
+
# person = Person.new
|
200
|
+
# person.name = 'Emmanuel'
|
201
|
+
# person.save
|
202
|
+
# person.name_previous_change # => [nil, 'Emmanuel']
|
203
|
+
|
204
|
+
##
|
205
|
+
# :method: *_previously_was
|
206
|
+
#
|
207
|
+
# This method is generated for each attribute.
|
208
|
+
#
|
209
|
+
# Returns the old value of the attribute before the last save.
|
210
|
+
#
|
211
|
+
# person = Person.new
|
212
|
+
# person.name = 'Sage'
|
213
|
+
# person.save
|
214
|
+
# person.name_previously_was # => nil
|
215
|
+
|
216
|
+
##
|
217
|
+
# :method: restore_*!
|
218
|
+
#
|
219
|
+
# This method is generated for each attribute.
|
220
|
+
#
|
221
|
+
# Restores the attribute to the old value.
|
222
|
+
#
|
223
|
+
# person = Person.new
|
224
|
+
# person.name = 'Amanda'
|
225
|
+
# person.restore_name!
|
226
|
+
# person.name # => nil
|
227
|
+
|
228
|
+
##
|
229
|
+
# :method: clear_*_change
|
230
|
+
#
|
231
|
+
# This method is generated for each attribute.
|
232
|
+
#
|
233
|
+
# Clears all dirty data of the attribute: current changes and previous changes.
|
234
|
+
#
|
235
|
+
# person = Person.new(name: 'Chris')
|
236
|
+
# person.name = 'Jason'
|
237
|
+
# person.name_change # => ['Chris', 'Jason']
|
238
|
+
# person.clear_name_change
|
239
|
+
# person.name_change # => nil
|
240
|
+
|
126
241
|
attribute_method_suffix "_previously_changed?", "_changed?", parameters: "**options"
|
127
242
|
attribute_method_suffix "_change", "_will_change!", "_was", parameters: false
|
128
243
|
attribute_method_suffix "_previous_change", "_previously_was", parameters: false
|
@@ -174,23 +289,23 @@ module ActiveModel
|
|
174
289
|
mutations_from_database.changed_attribute_names
|
175
290
|
end
|
176
291
|
|
177
|
-
# Dispatch target for
|
178
|
-
def attribute_changed?(attr_name, **options)
|
292
|
+
# Dispatch target for {*_changed?}[rdoc-label:method-i-2A_changed-3F] attribute methods.
|
293
|
+
def attribute_changed?(attr_name, **options)
|
179
294
|
mutations_from_database.changed?(attr_name.to_s, **options)
|
180
295
|
end
|
181
296
|
|
182
|
-
# Dispatch target for
|
183
|
-
def attribute_was(attr_name)
|
297
|
+
# Dispatch target for {*_was}[rdoc-label:method-i-2A_was] attribute methods.
|
298
|
+
def attribute_was(attr_name)
|
184
299
|
mutations_from_database.original_value(attr_name.to_s)
|
185
300
|
end
|
186
301
|
|
187
|
-
# Dispatch target for
|
188
|
-
def attribute_previously_changed?(attr_name, **options)
|
302
|
+
# Dispatch target for {*_previously_changed?}[rdoc-label:method-i-2A_previously_changed-3F] attribute methods.
|
303
|
+
def attribute_previously_changed?(attr_name, **options)
|
189
304
|
mutations_before_last_save.changed?(attr_name.to_s, **options)
|
190
305
|
end
|
191
306
|
|
192
|
-
# Dispatch target for
|
193
|
-
def attribute_previously_was(attr_name)
|
307
|
+
# Dispatch target for {*_previously_was}[rdoc-label:method-i-2A_previously_was] attribute methods.
|
308
|
+
def attribute_previously_was(attr_name)
|
194
309
|
mutations_before_last_save.original_value(attr_name.to_s)
|
195
310
|
end
|
196
311
|
|
@@ -247,6 +362,12 @@ module ActiveModel
|
|
247
362
|
end
|
248
363
|
|
249
364
|
private
|
365
|
+
def init_internals
|
366
|
+
super
|
367
|
+
@mutations_before_last_save = nil
|
368
|
+
@mutations_from_database = nil
|
369
|
+
end
|
370
|
+
|
250
371
|
def clear_attribute_change(attr_name)
|
251
372
|
mutations_from_database.forget_change(attr_name.to_s)
|
252
373
|
end
|
data/lib/active_model/error.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_support/core_ext/class/attribute"
|
4
4
|
|
5
5
|
module ActiveModel
|
6
|
-
#
|
6
|
+
# = Active \Model \Error
|
7
7
|
#
|
8
8
|
# Represents one single error
|
9
9
|
class Error
|
@@ -49,7 +49,7 @@ module ActiveModel
|
|
49
49
|
defaults << :"errors.format"
|
50
50
|
defaults << "%{attribute} %{message}"
|
51
51
|
|
52
|
-
attr_name = attribute.tr(".", "_").humanize
|
52
|
+
attr_name = attribute.remove(/\.base\z/).tr(".", "_").humanize
|
53
53
|
attr_name = base_class.human_attribute_name(attribute, {
|
54
54
|
default: attr_name,
|
55
55
|
base: base,
|
@@ -121,9 +121,10 @@ module ActiveModel
|
|
121
121
|
attr_reader :attribute
|
122
122
|
# The type of error, defaults to +:invalid+ unless specified
|
123
123
|
attr_reader :type
|
124
|
-
# The raw value provided as the second parameter when calling
|
124
|
+
# The raw value provided as the second parameter when calling
|
125
|
+
# <tt>errors#add</tt>
|
125
126
|
attr_reader :raw_type
|
126
|
-
# The options provided when calling
|
127
|
+
# The options provided when calling <tt>errors#add</tt>
|
127
128
|
attr_reader :options
|
128
129
|
|
129
130
|
# Returns the error message.
|
data/lib/active_model/errors.rb
CHANGED
@@ -3,13 +3,12 @@
|
|
3
3
|
require "active_support/core_ext/array/conversions"
|
4
4
|
require "active_support/core_ext/string/inflections"
|
5
5
|
require "active_support/core_ext/object/deep_dup"
|
6
|
-
require "active_support/core_ext/string/filters"
|
7
6
|
require "active_model/error"
|
8
7
|
require "active_model/nested_error"
|
9
8
|
require "forwardable"
|
10
9
|
|
11
10
|
module ActiveModel
|
12
|
-
#
|
11
|
+
# = Active \Model \Errors
|
13
12
|
#
|
14
13
|
# Provides error related functionalities you can include in your object
|
15
14
|
# for handling error messages and interacting with Action View helpers.
|
@@ -64,6 +63,7 @@ module ActiveModel
|
|
64
63
|
|
65
64
|
extend Forwardable
|
66
65
|
|
66
|
+
##
|
67
67
|
# :method: each
|
68
68
|
#
|
69
69
|
# :call-seq: each(&block)
|
@@ -75,6 +75,31 @@ module ActiveModel
|
|
75
75
|
# # Will yield <#ActiveModel::Error attribute=name, type=too_short,
|
76
76
|
# options={:count=>3}>
|
77
77
|
# end
|
78
|
+
|
79
|
+
##
|
80
|
+
# :method: clear
|
81
|
+
#
|
82
|
+
# :call-seq: clear
|
83
|
+
#
|
84
|
+
# Clears all errors. Clearing the errors does not, however, make the model
|
85
|
+
# valid. The next time the validations are run (for example, via
|
86
|
+
# ActiveRecord::Validations#valid?), the errors collection will be filled
|
87
|
+
# again if any validations fail.
|
88
|
+
|
89
|
+
##
|
90
|
+
# :method: empty?
|
91
|
+
#
|
92
|
+
# :call-seq: empty?
|
93
|
+
#
|
94
|
+
# Returns true if there are no errors.
|
95
|
+
|
96
|
+
##
|
97
|
+
# :method: size
|
98
|
+
#
|
99
|
+
# :call-seq: size
|
100
|
+
#
|
101
|
+
# Returns number of errors.
|
102
|
+
|
78
103
|
def_delegators :@errors, :each, :clear, :empty?, :size, :uniq!
|
79
104
|
|
80
105
|
# The actual array of +Error+ objects
|
@@ -215,7 +240,7 @@ module ActiveModel
|
|
215
240
|
|
216
241
|
# Returns a Hash that can be used as the JSON representation for this
|
217
242
|
# object. You can pass the <tt>:full_messages</tt> option. This determines
|
218
|
-
# if the
|
243
|
+
# if the JSON object should contain full messages or not (false by default).
|
219
244
|
#
|
220
245
|
# person.errors.as_json # => {:name=>["cannot be nil"]}
|
221
246
|
# person.errors.as_json(full_messages: true) # => {:name=>["name cannot be nil"]}
|
@@ -287,7 +312,7 @@ module ActiveModel
|
|
287
312
|
# person.errors.messages
|
288
313
|
# # => {:name=>["can't be blank"]}
|
289
314
|
#
|
290
|
-
# person.errors.add(:name, :too_long,
|
315
|
+
# person.errors.add(:name, :too_long, count: 25)
|
291
316
|
# person.errors.messages
|
292
317
|
# # => ["is too long (maximum is 25 characters)"]
|
293
318
|
#
|
@@ -338,7 +363,7 @@ module ActiveModel
|
|
338
363
|
# If the error requires options, then it returns +true+ with
|
339
364
|
# the correct options, or +false+ with incorrect or missing options.
|
340
365
|
#
|
341
|
-
# person.errors.add :name, :too_long,
|
366
|
+
# person.errors.add :name, :too_long, count: 25
|
342
367
|
# person.errors.added? :name, :too_long, count: 25 # => true
|
343
368
|
# person.errors.added? :name, "is too long (maximum is 25 characters)" # => true
|
344
369
|
# person.errors.added? :name, :too_long, count: 24 # => false
|
@@ -360,7 +385,7 @@ module ActiveModel
|
|
360
385
|
# present, or +false+ otherwise. +type+ is treated the same as for +add+.
|
361
386
|
#
|
362
387
|
# person.errors.add :age
|
363
|
-
# person.errors.add :name, :too_long,
|
388
|
+
# person.errors.add :name, :too_long, count: 25
|
364
389
|
# person.errors.of_kind? :age # => true
|
365
390
|
# person.errors.of_kind? :name # => false
|
366
391
|
# person.errors.of_kind? :name, :too_long # => true
|
@@ -472,6 +497,8 @@ module ActiveModel
|
|
472
497
|
end
|
473
498
|
end
|
474
499
|
|
500
|
+
# = Active \Model \StrictValidationFailed
|
501
|
+
#
|
475
502
|
# Raised when a validation cannot be corrected by end users and are considered
|
476
503
|
# exceptional.
|
477
504
|
#
|
@@ -490,10 +517,14 @@ module ActiveModel
|
|
490
517
|
class StrictValidationFailed < StandardError
|
491
518
|
end
|
492
519
|
|
520
|
+
# = Active \Model \RangeError
|
521
|
+
#
|
493
522
|
# Raised when attribute values are out of range.
|
494
523
|
class RangeError < ::RangeError
|
495
524
|
end
|
496
525
|
|
526
|
+
# = Active \Model \UnknownAttributeError
|
527
|
+
#
|
497
528
|
# Raised when unknown attributes are supplied via mass assignment.
|
498
529
|
#
|
499
530
|
# class Person
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveModel
|
4
|
-
# Returns the currently loaded version of \Active \Model as a
|
4
|
+
# Returns the currently loaded version of \Active \Model as a +Gem::Version+.
|
5
5
|
def self.gem_version
|
6
6
|
Gem::Version.new VERSION::STRING
|
7
7
|
end
|
8
8
|
|
9
9
|
module VERSION
|
10
10
|
MAJOR = 7
|
11
|
-
MINOR =
|
12
|
-
TINY =
|
13
|
-
PRE =
|
11
|
+
MINOR = 1
|
12
|
+
TINY = 3
|
13
|
+
PRE = "4"
|
14
14
|
|
15
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
16
16
|
end
|
data/lib/active_model/lint.rb
CHANGED
@@ -5,7 +5,7 @@ module ActiveModel
|
|
5
5
|
# == Active \Model \Lint \Tests
|
6
6
|
#
|
7
7
|
# You can test whether an object is compliant with the Active \Model API by
|
8
|
-
# including
|
8
|
+
# including +ActiveModel::Lint::Tests+ in your TestCase. It will
|
9
9
|
# include tests that tell you whether your object is fully compliant,
|
10
10
|
# or if not, which aspects of the API are not implemented.
|
11
11
|
#
|
@@ -18,6 +18,7 @@ en:
|
|
18
18
|
too_long:
|
19
19
|
one: "is too long (maximum is 1 character)"
|
20
20
|
other: "is too long (maximum is %{count} characters)"
|
21
|
+
password_too_long: "is too long"
|
21
22
|
too_short:
|
22
23
|
one: "is too short (minimum is 1 character)"
|
23
24
|
other: "is too short (minimum is %{count} characters)"
|
data/lib/active_model/model.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveModel
|
4
|
-
#
|
4
|
+
# = Active \Model \Basic \Model
|
5
5
|
#
|
6
6
|
# Allows implementing models similar to ActiveRecord::Base.
|
7
7
|
# Includes ActiveModel::API for the required interface for an
|
@@ -37,10 +37,42 @@ module ActiveModel
|
|
37
37
|
# person.omg # => true
|
38
38
|
#
|
39
39
|
# For more detailed information on other functionalities available, please
|
40
|
-
# refer to the specific modules included in
|
40
|
+
# refer to the specific modules included in +ActiveModel::Model+
|
41
41
|
# (see below).
|
42
42
|
module Model
|
43
43
|
extend ActiveSupport::Concern
|
44
44
|
include ActiveModel::API
|
45
|
+
include ActiveModel::Access
|
46
|
+
|
47
|
+
##
|
48
|
+
# :method: slice
|
49
|
+
#
|
50
|
+
# :call-seq: slice(*methods)
|
51
|
+
#
|
52
|
+
# Returns a hash of the given methods with their names as keys and returned
|
53
|
+
# values as values.
|
54
|
+
#
|
55
|
+
# person = Person.new(id: 1, name: "bob")
|
56
|
+
# person.slice(:id, :name)
|
57
|
+
# => { "id" => 1, "name" => "bob" }
|
58
|
+
#
|
59
|
+
#--
|
60
|
+
# Implemented by ActiveModel::Access#slice.
|
61
|
+
|
62
|
+
##
|
63
|
+
# :method: values_at
|
64
|
+
#
|
65
|
+
# :call-seq: values_at(*methods)
|
66
|
+
#
|
67
|
+
# Returns an array of the values returned by the given methods.
|
68
|
+
#
|
69
|
+
# person = Person.new(id: 1, name: "bob")
|
70
|
+
# person.values_at(:id, :name)
|
71
|
+
# => [1, "bob"]
|
72
|
+
#
|
73
|
+
#--
|
74
|
+
# Implemented by ActiveModel::Access#values_at.
|
45
75
|
end
|
76
|
+
|
77
|
+
ActiveSupport.run_load_hooks(:active_model, Model)
|
46
78
|
end
|
data/lib/active_model/naming.rb
CHANGED
@@ -195,18 +195,15 @@ module ActiveModel
|
|
195
195
|
#
|
196
196
|
# Specify +options+ with additional translating options.
|
197
197
|
def human(options = {})
|
198
|
-
return @human
|
199
|
-
@klass.respond_to?(:i18n_scope)
|
200
|
-
|
201
|
-
defaults = @klass.lookup_ancestors.map do |klass|
|
202
|
-
klass.model_name.i18n_key
|
203
|
-
end
|
198
|
+
return @human if i18n_keys.empty? || i18n_scope.empty?
|
204
199
|
|
200
|
+
key, *defaults = i18n_keys
|
205
201
|
defaults << options[:default] if options[:default]
|
206
|
-
defaults <<
|
202
|
+
defaults << MISSING_TRANSLATION
|
207
203
|
|
208
|
-
|
209
|
-
|
204
|
+
translation = I18n.translate(key, scope: i18n_scope, count: 1, **options, default: defaults)
|
205
|
+
translation = @human if translation == MISSING_TRANSLATION
|
206
|
+
translation
|
210
207
|
end
|
211
208
|
|
212
209
|
def uncountable?
|
@@ -214,12 +211,26 @@ module ActiveModel
|
|
214
211
|
end
|
215
212
|
|
216
213
|
private
|
214
|
+
MISSING_TRANSLATION = -(2**60) # :nodoc:
|
215
|
+
|
217
216
|
def _singularize(string)
|
218
217
|
ActiveSupport::Inflector.underscore(string).tr("/", "_")
|
219
218
|
end
|
219
|
+
|
220
|
+
def i18n_keys
|
221
|
+
@i18n_keys ||= if @klass.respond_to?(:lookup_ancestors)
|
222
|
+
@klass.lookup_ancestors.map { |klass| klass.model_name.i18n_key }
|
223
|
+
else
|
224
|
+
[]
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def i18n_scope
|
229
|
+
@i18n_scope ||= @klass.respond_to?(:i18n_scope) ? [@klass.i18n_scope, :models] : []
|
230
|
+
end
|
220
231
|
end
|
221
232
|
|
222
|
-
#
|
233
|
+
# = Active \Model \Naming
|
223
234
|
#
|
224
235
|
# Creates a +model_name+ method on your object.
|
225
236
|
#
|
@@ -336,5 +347,13 @@ module ActiveModel
|
|
336
347
|
end
|
337
348
|
end
|
338
349
|
private_class_method :model_name_from_record_or_class
|
350
|
+
|
351
|
+
private
|
352
|
+
def inherited(base)
|
353
|
+
super
|
354
|
+
base.class_eval do
|
355
|
+
@_model_name = nil
|
356
|
+
end
|
357
|
+
end
|
339
358
|
end
|
340
359
|
end
|
data/lib/active_model/railtie.rb
CHANGED
@@ -9,6 +9,10 @@ module ActiveModel
|
|
9
9
|
|
10
10
|
config.active_model = ActiveSupport::OrderedOptions.new
|
11
11
|
|
12
|
+
initializer "active_model.deprecator", before: :load_environment_config do |app|
|
13
|
+
app.deprecators[:active_model] = ActiveModel.deprecator
|
14
|
+
end
|
15
|
+
|
12
16
|
initializer "active_model.secure_password" do
|
13
17
|
ActiveModel::SecurePassword.min_cost = Rails.env.test?
|
14
18
|
end
|