activemodel 7.0.10 → 7.1.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +132 -236
- 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 -38
- 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 +5 -2
- 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 +5 -5
- 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 +18 -10
|
@@ -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.
|
|
@@ -64,7 +63,6 @@ module ActiveModel
|
|
|
64
63
|
|
|
65
64
|
extend Forwardable
|
|
66
65
|
|
|
67
|
-
##
|
|
68
66
|
# :method: each
|
|
69
67
|
#
|
|
70
68
|
# :call-seq: each(&block)
|
|
@@ -76,31 +74,6 @@ module ActiveModel
|
|
|
76
74
|
# # Will yield <#ActiveModel::Error attribute=name, type=too_short,
|
|
77
75
|
# options={:count=>3}>
|
|
78
76
|
# end
|
|
79
|
-
|
|
80
|
-
##
|
|
81
|
-
# :method: clear
|
|
82
|
-
#
|
|
83
|
-
# :call-seq: clear
|
|
84
|
-
#
|
|
85
|
-
# Clears all errors. Clearing the errors does not, however, make the model
|
|
86
|
-
# valid. The next time the validations are run (for example, via
|
|
87
|
-
# ActiveRecord::Validations#valid?), the errors collection will be filled
|
|
88
|
-
# again if any validations fail.
|
|
89
|
-
|
|
90
|
-
##
|
|
91
|
-
# :method: empty?
|
|
92
|
-
#
|
|
93
|
-
# :call-seq: empty?
|
|
94
|
-
#
|
|
95
|
-
# Returns true if there are no errors.
|
|
96
|
-
|
|
97
|
-
##
|
|
98
|
-
# :method: size
|
|
99
|
-
#
|
|
100
|
-
# :call-seq: size
|
|
101
|
-
#
|
|
102
|
-
# Returns number of errors.
|
|
103
|
-
|
|
104
77
|
def_delegators :@errors, :each, :clear, :empty?, :size, :uniq!
|
|
105
78
|
|
|
106
79
|
# The actual array of +Error+ objects
|
|
@@ -241,7 +214,7 @@ module ActiveModel
|
|
|
241
214
|
|
|
242
215
|
# Returns a Hash that can be used as the JSON representation for this
|
|
243
216
|
# object. You can pass the <tt>:full_messages</tt> option. This determines
|
|
244
|
-
# if the
|
|
217
|
+
# if the JSON object should contain full messages or not (false by default).
|
|
245
218
|
#
|
|
246
219
|
# person.errors.as_json # => {:name=>["cannot be nil"]}
|
|
247
220
|
# person.errors.as_json(full_messages: true) # => {:name=>["name cannot be nil"]}
|
|
@@ -311,9 +284,9 @@ module ActiveModel
|
|
|
311
284
|
#
|
|
312
285
|
# person.errors.add(:name, :blank)
|
|
313
286
|
# person.errors.messages
|
|
314
|
-
# # => {:name=>["can
|
|
287
|
+
# # => {:name=>["can’t be blank"]}
|
|
315
288
|
#
|
|
316
|
-
# person.errors.add(:name, :too_long,
|
|
289
|
+
# person.errors.add(:name, :too_long, count: 25)
|
|
317
290
|
# person.errors.messages
|
|
318
291
|
# # => ["is too long (maximum is 25 characters)"]
|
|
319
292
|
#
|
|
@@ -359,12 +332,12 @@ module ActiveModel
|
|
|
359
332
|
#
|
|
360
333
|
# person.errors.add :name, :blank
|
|
361
334
|
# person.errors.added? :name, :blank # => true
|
|
362
|
-
# person.errors.added? :name, "can
|
|
335
|
+
# person.errors.added? :name, "can’t be blank" # => true
|
|
363
336
|
#
|
|
364
337
|
# If the error requires options, then it returns +true+ with
|
|
365
338
|
# the correct options, or +false+ with incorrect or missing options.
|
|
366
339
|
#
|
|
367
|
-
# person.errors.add :name, :too_long,
|
|
340
|
+
# person.errors.add :name, :too_long, count: 25
|
|
368
341
|
# person.errors.added? :name, :too_long, count: 25 # => true
|
|
369
342
|
# person.errors.added? :name, "is too long (maximum is 25 characters)" # => true
|
|
370
343
|
# person.errors.added? :name, :too_long, count: 24 # => false
|
|
@@ -386,7 +359,7 @@ module ActiveModel
|
|
|
386
359
|
# present, or +false+ otherwise. +type+ is treated the same as for +add+.
|
|
387
360
|
#
|
|
388
361
|
# person.errors.add :age
|
|
389
|
-
# person.errors.add :name, :too_long,
|
|
362
|
+
# person.errors.add :name, :too_long, count: 25
|
|
390
363
|
# person.errors.of_kind? :age # => true
|
|
391
364
|
# person.errors.of_kind? :name # => false
|
|
392
365
|
# person.errors.of_kind? :name, :too_long # => true
|
|
@@ -412,7 +385,7 @@ module ActiveModel
|
|
|
412
385
|
#
|
|
413
386
|
# person = Person.create(address: '123 First St.')
|
|
414
387
|
# person.errors.full_messages
|
|
415
|
-
# # => ["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"]
|
|
416
389
|
def full_messages
|
|
417
390
|
@errors.map(&:full_message)
|
|
418
391
|
end
|
|
@@ -427,7 +400,7 @@ module ActiveModel
|
|
|
427
400
|
#
|
|
428
401
|
# person = Person.create()
|
|
429
402
|
# person.errors.full_messages_for(:name)
|
|
430
|
-
# # => ["Name is too short (minimum is 5 characters)", "Name can
|
|
403
|
+
# # => ["Name is too short (minimum is 5 characters)", "Name can’t be blank"]
|
|
431
404
|
def full_messages_for(attribute)
|
|
432
405
|
where(attribute).map(&:full_message).freeze
|
|
433
406
|
end
|
|
@@ -441,7 +414,7 @@ module ActiveModel
|
|
|
441
414
|
#
|
|
442
415
|
# person = Person.create()
|
|
443
416
|
# person.errors.messages_for(:name)
|
|
444
|
-
# # => ["is too short (minimum is 5 characters)", "can
|
|
417
|
+
# # => ["is too short (minimum is 5 characters)", "can’t be blank"]
|
|
445
418
|
def messages_for(attribute)
|
|
446
419
|
where(attribute).map(&:message)
|
|
447
420
|
end
|
|
@@ -498,6 +471,8 @@ module ActiveModel
|
|
|
498
471
|
end
|
|
499
472
|
end
|
|
500
473
|
|
|
474
|
+
# = Active \Model \StrictValidationFailed
|
|
475
|
+
#
|
|
501
476
|
# Raised when a validation cannot be corrected by end users and are considered
|
|
502
477
|
# exceptional.
|
|
503
478
|
#
|
|
@@ -512,14 +487,18 @@ module ActiveModel
|
|
|
512
487
|
# person = Person.new
|
|
513
488
|
# person.name = nil
|
|
514
489
|
# person.valid?
|
|
515
|
-
# # => ActiveModel::StrictValidationFailed: Name can
|
|
490
|
+
# # => ActiveModel::StrictValidationFailed: Name can’t be blank
|
|
516
491
|
class StrictValidationFailed < StandardError
|
|
517
492
|
end
|
|
518
493
|
|
|
494
|
+
# = Active \Model \RangeError
|
|
495
|
+
#
|
|
519
496
|
# Raised when attribute values are out of range.
|
|
520
497
|
class RangeError < ::RangeError
|
|
521
498
|
end
|
|
522
499
|
|
|
500
|
+
# = Active \Model \UnknownAttributeError
|
|
501
|
+
#
|
|
523
502
|
# Raised when unknown attributes are supplied via mass assignment.
|
|
524
503
|
#
|
|
525
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
|