activemodel 7.0.8.7 → 7.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -263
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_model/access.rb +16 -0
  6. data/lib/active_model/api.rb +5 -5
  7. data/lib/active_model/attribute/user_provided_default.rb +4 -0
  8. data/lib/active_model/attribute.rb +27 -2
  9. data/lib/active_model/attribute_assignment.rb +4 -2
  10. data/lib/active_model/attribute_methods.rb +145 -85
  11. data/lib/active_model/attribute_registration.rb +117 -0
  12. data/lib/active_model/attribute_set.rb +10 -1
  13. data/lib/active_model/attributes.rb +78 -48
  14. data/lib/active_model/callbacks.rb +6 -6
  15. data/lib/active_model/conversion.rb +14 -4
  16. data/lib/active_model/deprecator.rb +7 -0
  17. data/lib/active_model/dirty.rb +134 -13
  18. data/lib/active_model/error.rb +4 -3
  19. data/lib/active_model/errors.rb +37 -6
  20. data/lib/active_model/forbidden_attributes_protection.rb +2 -0
  21. data/lib/active_model/gem_version.rb +4 -4
  22. data/lib/active_model/lint.rb +1 -1
  23. data/lib/active_model/locale/en.yml +1 -0
  24. data/lib/active_model/model.rb +34 -2
  25. data/lib/active_model/naming.rb +29 -10
  26. data/lib/active_model/railtie.rb +4 -0
  27. data/lib/active_model/secure_password.rb +62 -24
  28. data/lib/active_model/serialization.rb +3 -3
  29. data/lib/active_model/serializers/json.rb +1 -1
  30. data/lib/active_model/translation.rb +18 -16
  31. data/lib/active_model/type/big_integer.rb +23 -1
  32. data/lib/active_model/type/binary.rb +7 -1
  33. data/lib/active_model/type/boolean.rb +11 -9
  34. data/lib/active_model/type/date.rb +28 -2
  35. data/lib/active_model/type/date_time.rb +45 -3
  36. data/lib/active_model/type/decimal.rb +39 -1
  37. data/lib/active_model/type/float.rb +30 -1
  38. data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +5 -1
  39. data/lib/active_model/type/helpers/numeric.rb +6 -1
  40. data/lib/active_model/type/helpers/time_value.rb +50 -13
  41. data/lib/active_model/type/helpers/timezone.rb +5 -1
  42. data/lib/active_model/type/immutable_string.rb +37 -1
  43. data/lib/active_model/type/integer.rb +44 -1
  44. data/lib/active_model/type/registry.rb +2 -3
  45. data/lib/active_model/type/serialize_cast_value.rb +47 -0
  46. data/lib/active_model/type/string.rb +9 -1
  47. data/lib/active_model/type/time.rb +48 -7
  48. data/lib/active_model/type/value.rb +17 -1
  49. data/lib/active_model/type.rb +1 -0
  50. data/lib/active_model/validations/absence.rb +1 -1
  51. data/lib/active_model/validations/acceptance.rb +1 -1
  52. data/lib/active_model/validations/callbacks.rb +5 -5
  53. data/lib/active_model/validations/clusivity.rb +5 -8
  54. data/lib/active_model/validations/comparability.rb +0 -11
  55. data/lib/active_model/validations/comparison.rb +16 -8
  56. data/lib/active_model/validations/format.rb +6 -7
  57. data/lib/active_model/validations/length.rb +10 -8
  58. data/lib/active_model/validations/numericality.rb +35 -23
  59. data/lib/active_model/validations/presence.rb +1 -1
  60. data/lib/active_model/validations/resolve_value.rb +26 -0
  61. data/lib/active_model/validations/validates.rb +4 -4
  62. data/lib/active_model/validations/with.rb +9 -2
  63. data/lib/active_model/validations.rb +44 -9
  64. data/lib/active_model/validator.rb +7 -5
  65. data/lib/active_model/version.rb +1 -1
  66. data/lib/active_model.rb +5 -1
  67. metadata +12 -7
@@ -1,33 +1,67 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_model/attribute_set"
4
- require "active_model/attribute/user_provided_default"
5
-
6
3
  module ActiveModel
7
- module Attributes # :nodoc:
4
+ # = Active \Model \Attributes
5
+ #
6
+ # The Attributes module allows models to define attributes beyond simple Ruby
7
+ # readers and writers. Similar to Active Record attributes, which are
8
+ # typically inferred from the database schema, Active Model Attributes are
9
+ # aware of data types, can have default values, and can handle casting and
10
+ # serialization.
11
+ #
12
+ # To use Attributes, include the module in your model class and define your
13
+ # attributes using the +attribute+ macro. It accepts a name, a type, a default
14
+ # value, and any other options supported by the attribute type.
15
+ #
16
+ # ==== Examples
17
+ #
18
+ # class Person
19
+ # include ActiveModel::Attributes
20
+ #
21
+ # attribute :name, :string
22
+ # attribute :active, :boolean, default: true
23
+ # end
24
+ #
25
+ # person = Person.new
26
+ # person.name = "Volmer"
27
+ #
28
+ # person.name # => "Volmer"
29
+ # person.active # => true
30
+ module Attributes
8
31
  extend ActiveSupport::Concern
32
+ include ActiveModel::AttributeRegistration
9
33
  include ActiveModel::AttributeMethods
10
34
 
11
35
  included do
12
36
  attribute_method_suffix "=", parameters: "value"
13
- class_attribute :attribute_types, :_default_attributes, instance_accessor: false
14
- self.attribute_types = Hash.new(Type.default_value)
15
- self._default_attributes = AttributeSet.new({})
16
37
  end
17
38
 
18
39
  module ClassMethods
19
- def attribute(name, cast_type = nil, default: NO_DEFAULT_PROVIDED, **options)
20
- name = name.to_s
21
-
22
- cast_type = Type.lookup(cast_type, **options) if Symbol === cast_type
23
- cast_type ||= attribute_types[name]
24
-
25
- self.attribute_types = attribute_types.merge(name => cast_type)
26
- define_default_attribute(name, default, cast_type)
40
+ ##
41
+ # :call-seq: attribute(name, cast_type = nil, default: nil, **options)
42
+ #
43
+ # Defines a model attribute. In addition to the attribute name, a cast
44
+ # type and default value may be specified, as well as any options
45
+ # supported by the given cast type.
46
+ #
47
+ # class Person
48
+ # include ActiveModel::Attributes
49
+ #
50
+ # attribute :name, :string
51
+ # attribute :active, :boolean, default: true
52
+ # end
53
+ #
54
+ # person = Person.new
55
+ # person.name = "Volmer"
56
+ #
57
+ # person.name # => "Volmer"
58
+ # person.active # => true
59
+ def attribute(name, ...)
60
+ super
27
61
  define_attribute_method(name)
28
62
  end
29
63
 
30
- # Returns an array of attribute names as strings
64
+ # Returns an array of attribute names as strings.
31
65
  #
32
66
  # class Person
33
67
  # include ActiveModel::Attributes
@@ -36,18 +70,30 @@ module ActiveModel
36
70
  # attribute :age, :integer
37
71
  # end
38
72
  #
39
- # Person.attribute_names
40
- # # => ["name", "age"]
73
+ # Person.attribute_names # => ["name", "age"]
41
74
  def attribute_names
42
75
  attribute_types.keys
43
76
  end
44
77
 
78
+ ##
79
+ # :method: type_for_attribute
80
+ # :call-seq: type_for_attribute(attribute_name, &block)
81
+ #
82
+ # Returns the type of the specified attribute after applying any
83
+ # modifiers. This method is the only valid source of information for
84
+ # anything related to the types of a model's attributes. The return value
85
+ # of this method will implement the interface described by
86
+ # ActiveModel::Type::Value (though the object itself may not subclass it).
87
+ #--
88
+ # Implemented by ActiveModel::AttributeRegistration::ClassMethods#type_for_attribute.
89
+
90
+ ##
45
91
  private
46
- def define_method_attribute=(name, owner:)
92
+ def define_method_attribute=(canonical_name, owner:, as: canonical_name)
47
93
  ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
48
- owner, name, writer: true,
94
+ owner, canonical_name, writer: true,
49
95
  ) do |temp_method_name, attr_name_expr|
50
- owner.define_cached_method("#{name}=", as: temp_method_name, namespace: :active_model) do |batch|
96
+ owner.define_cached_method(temp_method_name, as: "#{as}=", namespace: :active_model) do |batch|
51
97
  batch <<
52
98
  "def #{temp_method_name}(value)" <<
53
99
  " _write_attribute(#{attr_name_expr}, value)" <<
@@ -55,27 +101,9 @@ module ActiveModel
55
101
  end
56
102
  end
57
103
  end
58
-
59
- NO_DEFAULT_PROVIDED = Object.new # :nodoc:
60
- private_constant :NO_DEFAULT_PROVIDED
61
-
62
- def define_default_attribute(name, value, type)
63
- self._default_attributes = _default_attributes.deep_dup
64
- if value == NO_DEFAULT_PROVIDED
65
- default_attribute = _default_attributes[name].with_type(type)
66
- else
67
- default_attribute = Attribute::UserProvidedDefault.new(
68
- name,
69
- value,
70
- type,
71
- _default_attributes.fetch(name.to_s) { nil },
72
- )
73
- end
74
- _default_attributes[name] = default_attribute
75
- end
76
104
  end
77
105
 
78
- def initialize(*)
106
+ def initialize(*) # :nodoc:
79
107
  @attributes = self.class._default_attributes.deep_dup
80
108
  super
81
109
  end
@@ -85,7 +113,8 @@ module ActiveModel
85
113
  super
86
114
  end
87
115
 
88
- # Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
116
+ # Returns a hash of all the attributes with their names as keys and the
117
+ # values of the attributes as values.
89
118
  #
90
119
  # class Person
91
120
  # include ActiveModel::Attributes
@@ -94,14 +123,16 @@ module ActiveModel
94
123
  # attribute :age, :integer
95
124
  # end
96
125
  #
97
- # person = Person.new(name: 'Francesco', age: 22)
98
- # person.attributes
99
- # # => {"name"=>"Francesco", "age"=>22}
126
+ # person = Person.new
127
+ # person.name = "Francesco"
128
+ # person.age = 22
129
+ #
130
+ # person.attributes # => { "name" => "Francesco", "age" => 22}
100
131
  def attributes
101
132
  @attributes.to_hash
102
133
  end
103
134
 
104
- # Returns an array of attribute names as strings
135
+ # Returns an array of attribute names as strings.
105
136
  #
106
137
  # class Person
107
138
  # include ActiveModel::Attributes
@@ -111,13 +142,12 @@ module ActiveModel
111
142
  # end
112
143
  #
113
144
  # person = Person.new
114
- # person.attribute_names
115
- # # => ["name", "age"]
145
+ # person.attribute_names # => ["name", "age"]
116
146
  def attribute_names
117
147
  @attributes.keys
118
148
  end
119
149
 
120
- def freeze
150
+ def freeze # :nodoc:
121
151
  @attributes = @attributes.clone.freeze unless frozen?
122
152
  super
123
153
  end
@@ -4,14 +4,14 @@ require "active_support/core_ext/array/extract_options"
4
4
  require "active_support/core_ext/hash/keys"
5
5
 
6
6
  module ActiveModel
7
- # == Active \Model \Callbacks
7
+ # = Active \Model \Callbacks
8
8
  #
9
9
  # Provides an interface for any class to have Active Record like callbacks.
10
10
  #
11
11
  # Like the Active Record methods, the callback chain is aborted as soon as
12
12
  # one of the methods throws +:abort+.
13
13
  #
14
- # First, extend ActiveModel::Callbacks from the class you are creating:
14
+ # First, extend +ActiveModel::Callbacks+ from the class you are creating:
15
15
  #
16
16
  # class MyModel
17
17
  # extend ActiveModel::Callbacks
@@ -60,7 +60,7 @@ module ActiveModel
60
60
  # Would only create the +after_create+ and +before_create+ callback methods in
61
61
  # your class.
62
62
  #
63
- # NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
63
+ # NOTE: Defining the same callback multiple times will overwrite previous callback definitions.
64
64
  #
65
65
  module Callbacks
66
66
  def self.extended(base) # :nodoc:
@@ -69,7 +69,7 @@ module ActiveModel
69
69
  end
70
70
  end
71
71
 
72
- # define_model_callbacks accepts the same options +define_callbacks+ does,
72
+ # +define_model_callbacks+ accepts the same options +define_callbacks+ does,
73
73
  # in case you want to overwrite a default. Besides that, it also accepts an
74
74
  # <tt>:only</tt> option, where you can choose if you want all types (before,
75
75
  # around or after) or just some.
@@ -77,7 +77,7 @@ module ActiveModel
77
77
  # define_model_callbacks :initialize, only: :after
78
78
  #
79
79
  # Note, the <tt>only: <type></tt> hash will apply to all callbacks defined
80
- # on that method call. To get around this you can call the define_model_callbacks
80
+ # on that method call. To get around this you can call the +define_model_callbacks+
81
81
  # method as many times as you need.
82
82
  #
83
83
  # define_model_callbacks :create, only: :after
@@ -104,7 +104,7 @@ module ActiveModel
104
104
  # end
105
105
  # end
106
106
  #
107
- # NOTE: +method_name+ passed to define_model_callbacks must not end with
107
+ # NOTE: +method_name+ passed to +define_model_callbacks+ must not end with
108
108
  # <tt>!</tt>, <tt>?</tt> or <tt>=</tt>.
109
109
  def define_model_callbacks(*callbacks)
110
110
  options = callbacks.extract_options!
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveModel
4
- # == Active \Model \Conversion
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 ? [key] : nil
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("-") : nil
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 ||= begin
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}"
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ def self.deprecator # :nodoc:
5
+ @deprecator ||= ActiveSupport::Deprecation.new
6
+ end
7
+ end
@@ -3,7 +3,7 @@
3
3
  require "active_model/attribute_mutation_tracker"
4
4
 
5
5
  module ActiveModel
6
- # == Active \Model \Dirty
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>[attr_name]_will_change!</tt> before each change to the tracked
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
- # <tt>[attribute_name]_will_change!</tt> to mark that the attribute is changing.
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>[attribute_name]_will_change!</tt> on Active Record models.
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 <tt>*_changed?</tt> attribute methods.
178
- def attribute_changed?(attr_name, **options) # :nodoc:
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 <tt>*_was</tt> attribute methods.
183
- def attribute_was(attr_name) # :nodoc:
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 <tt>*_previously_changed?</tt> attribute methods.
188
- def attribute_previously_changed?(attr_name, **options) # :nodoc:
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 <tt>*_previously_was</tt> attribute methods.
193
- def attribute_previously_was(attr_name) # :nodoc:
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
@@ -3,7 +3,7 @@
3
3
  require "active_support/core_ext/class/attribute"
4
4
 
5
5
  module ActiveModel
6
- # == Active \Model \Error
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 +errors#add+
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 +errors#add+
127
+ # The options provided when calling <tt>errors#add</tt>
127
128
  attr_reader :options
128
129
 
129
130
  # Returns the error message.
@@ -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
- # == Active \Model \Errors
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 json object should contain full messages or not (false by default).
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, { count: 25 })
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, { count: 25 }
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, { count: 25 }
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,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveModel
4
+ # = Active \Model \ForbiddenAttributesError
5
+ #
4
6
  # Raised when forbidden attributes are used for mass assignment.
5
7
  #
6
8
  # class Person < ActiveRecord::Base
@@ -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 <tt>Gem::Version</tt>.
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 = 0
12
- TINY = 8
13
- PRE = "7"
11
+ MINOR = 2
12
+ TINY = 2
13
+ PRE = "1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -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 <tt>ActiveModel::Lint::Tests</tt> in your TestCase. It will
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
  #