activemodel 7.0.8 → 7.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +132 -191
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -9
- 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 +102 -63
- data/lib/active_model/attribute_registration.rb +77 -0
- data/lib/active_model/attribute_set.rb +9 -0
- 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 +4 -3
- data/lib/active_model/errors.rb +17 -12
- 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 +4 -3
- data/lib/active_model/model.rb +26 -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 +7 -1
- 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/numeric.rb +4 -0
- 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 +17 -1
- 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/confirmation.rb +1 -1
- 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 +2 -2
- 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 +45 -10
- data/lib/active_model/validator.rb +7 -5
- data/lib/active_model/version.rb +1 -1
- data/lib/active_model.rb +5 -1
- metadata +14 -9
@@ -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_change # => ['Steph', 'Stephanie']
|
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
|
@@ -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.
|
@@ -215,7 +214,7 @@ module ActiveModel
|
|
215
214
|
|
216
215
|
# Returns a Hash that can be used as the JSON representation for this
|
217
216
|
# object. You can pass the <tt>:full_messages</tt> option. This determines
|
218
|
-
# if the
|
217
|
+
# if the JSON object should contain full messages or not (false by default).
|
219
218
|
#
|
220
219
|
# person.errors.as_json # => {:name=>["cannot be nil"]}
|
221
220
|
# person.errors.as_json(full_messages: true) # => {:name=>["name cannot be nil"]}
|
@@ -285,9 +284,9 @@ module ActiveModel
|
|
285
284
|
#
|
286
285
|
# person.errors.add(:name, :blank)
|
287
286
|
# person.errors.messages
|
288
|
-
# # => {:name=>["can
|
287
|
+
# # => {:name=>["can’t be blank"]}
|
289
288
|
#
|
290
|
-
# person.errors.add(:name, :too_long,
|
289
|
+
# person.errors.add(:name, :too_long, count: 25)
|
291
290
|
# person.errors.messages
|
292
291
|
# # => ["is too long (maximum is 25 characters)"]
|
293
292
|
#
|
@@ -333,12 +332,12 @@ module ActiveModel
|
|
333
332
|
#
|
334
333
|
# person.errors.add :name, :blank
|
335
334
|
# person.errors.added? :name, :blank # => true
|
336
|
-
# person.errors.added? :name, "can
|
335
|
+
# person.errors.added? :name, "can’t be blank" # => true
|
337
336
|
#
|
338
337
|
# If the error requires options, then it returns +true+ with
|
339
338
|
# the correct options, or +false+ with incorrect or missing options.
|
340
339
|
#
|
341
|
-
# person.errors.add :name, :too_long,
|
340
|
+
# person.errors.add :name, :too_long, count: 25
|
342
341
|
# person.errors.added? :name, :too_long, count: 25 # => true
|
343
342
|
# person.errors.added? :name, "is too long (maximum is 25 characters)" # => true
|
344
343
|
# person.errors.added? :name, :too_long, count: 24 # => false
|
@@ -360,7 +359,7 @@ module ActiveModel
|
|
360
359
|
# present, or +false+ otherwise. +type+ is treated the same as for +add+.
|
361
360
|
#
|
362
361
|
# person.errors.add :age
|
363
|
-
# person.errors.add :name, :too_long,
|
362
|
+
# person.errors.add :name, :too_long, count: 25
|
364
363
|
# person.errors.of_kind? :age # => true
|
365
364
|
# person.errors.of_kind? :name # => false
|
366
365
|
# person.errors.of_kind? :name, :too_long # => true
|
@@ -386,7 +385,7 @@ module ActiveModel
|
|
386
385
|
#
|
387
386
|
# person = Person.create(address: '123 First St.')
|
388
387
|
# person.errors.full_messages
|
389
|
-
# # => ["Name is too short (minimum is 5 characters)", "Name can
|
388
|
+
# # => ["Name is too short (minimum is 5 characters)", "Name can’t be blank", "Email can’t be blank"]
|
390
389
|
def full_messages
|
391
390
|
@errors.map(&:full_message)
|
392
391
|
end
|
@@ -401,7 +400,7 @@ module ActiveModel
|
|
401
400
|
#
|
402
401
|
# person = Person.create()
|
403
402
|
# person.errors.full_messages_for(:name)
|
404
|
-
# # => ["Name is too short (minimum is 5 characters)", "Name can
|
403
|
+
# # => ["Name is too short (minimum is 5 characters)", "Name can’t be blank"]
|
405
404
|
def full_messages_for(attribute)
|
406
405
|
where(attribute).map(&:full_message).freeze
|
407
406
|
end
|
@@ -415,7 +414,7 @@ module ActiveModel
|
|
415
414
|
#
|
416
415
|
# person = Person.create()
|
417
416
|
# person.errors.messages_for(:name)
|
418
|
-
# # => ["is too short (minimum is 5 characters)", "can
|
417
|
+
# # => ["is too short (minimum is 5 characters)", "can’t be blank"]
|
419
418
|
def messages_for(attribute)
|
420
419
|
where(attribute).map(&:message)
|
421
420
|
end
|
@@ -472,6 +471,8 @@ module ActiveModel
|
|
472
471
|
end
|
473
472
|
end
|
474
473
|
|
474
|
+
# = Active \Model \StrictValidationFailed
|
475
|
+
#
|
475
476
|
# Raised when a validation cannot be corrected by end users and are considered
|
476
477
|
# exceptional.
|
477
478
|
#
|
@@ -486,14 +487,18 @@ module ActiveModel
|
|
486
487
|
# person = Person.new
|
487
488
|
# person.name = nil
|
488
489
|
# person.valid?
|
489
|
-
# # => ActiveModel::StrictValidationFailed: Name can
|
490
|
+
# # => ActiveModel::StrictValidationFailed: Name can’t be blank
|
490
491
|
class StrictValidationFailed < StandardError
|
491
492
|
end
|
492
493
|
|
494
|
+
# = Active \Model \RangeError
|
495
|
+
#
|
493
496
|
# Raised when attribute values are out of range.
|
494
497
|
class RangeError < ::RangeError
|
495
498
|
end
|
496
499
|
|
500
|
+
# = Active \Model \UnknownAttributeError
|
501
|
+
#
|
497
502
|
# Raised when unknown attributes are supplied via mass assignment.
|
498
503
|
#
|
499
504
|
# 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 = 0
|
13
|
+
PRE = "beta1"
|
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
|
#
|
@@ -10,14 +10,15 @@ en:
|
|
10
10
|
inclusion: "is not included in the list"
|
11
11
|
exclusion: "is reserved"
|
12
12
|
invalid: "is invalid"
|
13
|
-
confirmation: "doesn
|
13
|
+
confirmation: "doesn’t match %{attribute}"
|
14
14
|
accepted: "must be accepted"
|
15
|
-
empty: "can
|
16
|
-
blank: "can
|
15
|
+
empty: "can’t be empty"
|
16
|
+
blank: "can’t be blank"
|
17
17
|
present: "must be blank"
|
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,34 @@ 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
|
+
#--
|
56
|
+
# Implemented by ActiveModel::Access#slice.
|
57
|
+
|
58
|
+
##
|
59
|
+
# :method: values_at
|
60
|
+
#
|
61
|
+
# :call-seq: values_at(*methods)
|
62
|
+
#
|
63
|
+
# Returns an array of the values returned by the given methods.
|
64
|
+
#
|
65
|
+
#--
|
66
|
+
# Implemented by ActiveModel::Access#values_at.
|
45
67
|
end
|
68
|
+
|
69
|
+
ActiveSupport.run_load_hooks(:active_model, Model)
|
46
70
|
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
|