activemodel 5.2.0.rc1 → 5.2.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 666a46bf39ff339f606b0d60219d61138a7de2def4808f6135255ee2a2b43ff0
4
- data.tar.gz: 5de9942d5e2dfd21df46a9ac538bc83b4bc879c57884e3f26192f4204dac6d33
3
+ metadata.gz: 97b6d1fb9b61ef956d88c6ee764394e9ccc0fcad2333073a876066fd9c7fcb7a
4
+ data.tar.gz: 86e60a71d98b585c900c3351a4c4fcf1f16ac73e4c0fc0b4595a443733c31f50
5
5
  SHA512:
6
- metadata.gz: f1f362e75e4a2cf7f08d2a89c2c8465516a72f014fc9d5d230a5cbc18195a4c734deb1b0c5bdede79d7126c7450154218b33824b5ab7b778ce033a800f156c68
7
- data.tar.gz: b00a94be4f5c30d482412abfb0e395c46804195b6c64ab57ba0f4cb4f01481bf2ff6ae4b32f0b51177859b496f8253413bbe8672602390f80b71df7a31b8a500
6
+ metadata.gz: 3d11a69342faac6bed87647ec40059830c8441459f30a6c9d94f3656ff2ce89a08fe3b12eed6846bae3352eb5fb929d4e30ab91611e569e7dae5f9e851fe47ba
7
+ data.tar.gz: 3493c445e4a3db83fcad5b043a82d16cf1242286bd49e73755bebf82a17f6b0f8f78d9563d2eac7d6ba739dc921b8a9a8a9ce2108098e4aab72bfa335658feec
@@ -1,3 +1,10 @@
1
+ ## Rails 5.2.0.rc2 (March 20, 2018) ##
2
+
3
+ * Do not lose all multiple `:includes` with options in serialization.
4
+
5
+ *Mike Mangino*
6
+
7
+
1
8
  ## Rails 5.2.0.rc1 (January 30, 2018) ##
2
9
 
3
10
  * Models using the attributes API with a proc default can now be marshalled.
@@ -239,7 +239,7 @@ The latest version of Active Model can be installed with RubyGems:
239
239
 
240
240
  Source code can be downloaded as part of the Rails project on GitHub
241
241
 
242
- * https://github.com/rails/rails/tree/master/activemodel
242
+ * https://github.com/rails/rails/tree/5-2-stable/activemodel
243
243
 
244
244
 
245
245
  == License
@@ -35,6 +35,8 @@ module ActiveModel
35
35
  _assign_attributes(sanitize_for_mass_assignment(attributes))
36
36
  end
37
37
 
38
+ alias attributes= assign_attributes
39
+
38
40
  private
39
41
 
40
42
  def _assign_attributes(attributes)
@@ -35,10 +35,6 @@ module ActiveModel
35
35
  end
36
36
  end
37
37
 
38
- def changed_attribute_names
39
- attr_names.select { |attr| changed?(attr) }
40
- end
41
-
42
38
  def any_changes?
43
39
  attr_names.any? { |attr| changed?(attr) }
44
40
  end
@@ -113,5 +109,8 @@ module ActiveModel
113
109
 
114
110
  def original_value(*)
115
111
  end
112
+
113
+ def force_change(*)
114
+ end
116
115
  end
117
116
  end
@@ -22,12 +22,12 @@ module ActiveModel
22
22
  class LazyAttributeHash # :nodoc:
23
23
  delegate :transform_values, :each_key, :each_value, :fetch, :except, to: :materialize
24
24
 
25
- def initialize(types, values, additional_types, default_attributes)
25
+ def initialize(types, values, additional_types, default_attributes, delegate_hash = {})
26
26
  @types = types
27
27
  @values = values
28
28
  @additional_types = additional_types
29
29
  @materialized = false
30
- @delegate_hash = {}
30
+ @delegate_hash = delegate_hash
31
31
  @default_attributes = default_attributes
32
32
  end
33
33
 
@@ -76,15 +76,17 @@ module ActiveModel
76
76
  end
77
77
 
78
78
  def marshal_dump
79
- materialize
79
+ [@types, @values, @additional_types, @default_attributes, @delegate_hash]
80
80
  end
81
81
 
82
- def marshal_load(delegate_hash)
83
- @delegate_hash = delegate_hash
84
- @types = {}
85
- @values = {}
86
- @additional_types = {}
87
- @materialized = true
82
+ def marshal_load(values)
83
+ if values.is_a?(Hash)
84
+ empty_hash = {}.freeze
85
+ initialize(empty_hash, empty_hash, empty_hash, empty_hash, values)
86
+ @materialized = true
87
+ else
88
+ initialize(*values)
89
+ end
88
90
  end
89
91
 
90
92
  protected
@@ -66,6 +66,10 @@ module ActiveModel
66
66
  super
67
67
  end
68
68
 
69
+ def attributes
70
+ @attributes.to_hash
71
+ end
72
+
69
73
  private
70
74
 
71
75
  def write_attribute(attr_name, value)
@@ -3,7 +3,6 @@
3
3
  require "active_support/hash_with_indifferent_access"
4
4
  require "active_support/core_ext/object/duplicable"
5
5
  require "active_model/attribute_mutation_tracker"
6
- require "active_model/attribute_set"
7
6
 
8
7
  module ActiveModel
9
8
  # == Active \Model \Dirty
@@ -143,8 +142,11 @@ module ActiveModel
143
142
  end
144
143
 
145
144
  def changes_applied # :nodoc:
146
- _prepare_changes
145
+ unless defined?(@attributes)
146
+ @previously_changed = changes
147
+ end
147
148
  @mutations_before_last_save = mutations_from_database
149
+ @attributes_changed_by_setter = ActiveSupport::HashWithIndifferentAccess.new
148
150
  forget_attribute_assignments
149
151
  @mutations_from_database = nil
150
152
  end
@@ -155,7 +157,7 @@ module ActiveModel
155
157
  # person.name = 'bob'
156
158
  # person.changed? # => true
157
159
  def changed?
158
- mutations_from_database.any_changes?
160
+ changed_attributes.present?
159
161
  end
160
162
 
161
163
  # Returns an array with the name of the attributes with unsaved changes.
@@ -164,24 +166,24 @@ module ActiveModel
164
166
  # person.name = 'bob'
165
167
  # person.changed # => ["name"]
166
168
  def changed
167
- mutations_from_database.changed_attribute_names
169
+ changed_attributes.keys
168
170
  end
169
171
 
170
172
  # Handles <tt>*_changed?</tt> for +method_missing+.
171
173
  def attribute_changed?(attr, from: OPTION_NOT_GIVEN, to: OPTION_NOT_GIVEN) # :nodoc:
172
- !!mutations_from_database.changed?(attr) &&
174
+ !!changes_include?(attr) &&
173
175
  (to == OPTION_NOT_GIVEN || to == _read_attribute(attr)) &&
174
- (from == OPTION_NOT_GIVEN || from == attribute_was(attr))
176
+ (from == OPTION_NOT_GIVEN || from == changed_attributes[attr])
175
177
  end
176
178
 
177
179
  # Handles <tt>*_was</tt> for +method_missing+.
178
180
  def attribute_was(attr) # :nodoc:
179
- mutations_from_database.original_value(attr)
181
+ attribute_changed?(attr) ? changed_attributes[attr] : _read_attribute(attr)
180
182
  end
181
183
 
182
184
  # Handles <tt>*_previously_changed?</tt> for +method_missing+.
183
185
  def attribute_previously_changed?(attr) #:nodoc:
184
- mutations_before_last_save.changed?(attr)
186
+ previous_changes_include?(attr)
185
187
  end
186
188
 
187
189
  # Restore all previous data of the provided attributes.
@@ -191,12 +193,15 @@ module ActiveModel
191
193
 
192
194
  # Clears all dirty data: current changes and previous changes.
193
195
  def clear_changes_information
196
+ @previously_changed = ActiveSupport::HashWithIndifferentAccess.new
194
197
  @mutations_before_last_save = nil
198
+ @attributes_changed_by_setter = ActiveSupport::HashWithIndifferentAccess.new
195
199
  forget_attribute_assignments
196
200
  @mutations_from_database = nil
197
201
  end
198
202
 
199
203
  def clear_attribute_changes(attr_names)
204
+ attributes_changed_by_setter.except!(*attr_names)
200
205
  attr_names.each do |attr_name|
201
206
  clear_attribute_change(attr_name)
202
207
  end
@@ -209,7 +214,13 @@ module ActiveModel
209
214
  # person.name = 'robert'
210
215
  # person.changed_attributes # => {"name" => "bob"}
211
216
  def changed_attributes
212
- mutations_from_database.changed_values.freeze
217
+ # This should only be set by methods which will call changed_attributes
218
+ # multiple times when it is known that the computed value cannot change.
219
+ if defined?(@cached_changed_attributes)
220
+ @cached_changed_attributes
221
+ else
222
+ attributes_changed_by_setter.reverse_merge(mutations_from_database.changed_values).freeze
223
+ end
213
224
  end
214
225
 
215
226
  # Returns a hash of changed attributes indicating their original
@@ -219,8 +230,9 @@ module ActiveModel
219
230
  # person.name = 'bob'
220
231
  # person.changes # => { "name" => ["bill", "bob"] }
221
232
  def changes
222
- _prepare_changes
223
- mutations_from_database.changes
233
+ cache_changed_attributes do
234
+ ActiveSupport::HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
235
+ end
224
236
  end
225
237
 
226
238
  # Returns a hash of attributes that were changed before the model was saved.
@@ -230,7 +242,8 @@ module ActiveModel
230
242
  # person.save
231
243
  # person.previous_changes # => {"name" => ["bob", "robert"]}
232
244
  def previous_changes
233
- mutations_before_last_save.changes
245
+ @previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new
246
+ @previously_changed.merge(mutations_before_last_save.changes)
234
247
  end
235
248
 
236
249
  def attribute_changed_in_place?(attr_name) # :nodoc:
@@ -246,17 +259,11 @@ module ActiveModel
246
259
  unless defined?(@mutations_from_database)
247
260
  @mutations_from_database = nil
248
261
  end
249
-
250
- unless defined?(@attributes)
251
- @_pseudo_attributes = true
252
- @attributes = AttributeSet.new(
253
- Hash.new { |h, attr|
254
- h[attr] = Attribute.with_cast_value(attr, _clone_attribute(attr), Type.default_value)
255
- }
256
- )
262
+ @mutations_from_database ||= if defined?(@attributes)
263
+ ActiveModel::AttributeMutationTracker.new(@attributes)
264
+ else
265
+ NullMutationTracker.instance
257
266
  end
258
-
259
- @mutations_from_database ||= ActiveModel::AttributeMutationTracker.new(@attributes)
260
267
  end
261
268
 
262
269
  def forget_attribute_assignments
@@ -267,45 +274,68 @@ module ActiveModel
267
274
  @mutations_before_last_save ||= ActiveModel::NullMutationTracker.instance
268
275
  end
269
276
 
277
+ def cache_changed_attributes
278
+ @cached_changed_attributes = changed_attributes
279
+ yield
280
+ ensure
281
+ clear_changed_attributes_cache
282
+ end
283
+
284
+ def clear_changed_attributes_cache
285
+ remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes)
286
+ end
287
+
288
+ # Returns +true+ if attr_name is changed, +false+ otherwise.
289
+ def changes_include?(attr_name)
290
+ attributes_changed_by_setter.include?(attr_name) || mutations_from_database.changed?(attr_name)
291
+ end
292
+ alias attribute_changed_by_setter? changes_include?
293
+
294
+ # Returns +true+ if attr_name were changed before the model was saved,
295
+ # +false+ otherwise.
296
+ def previous_changes_include?(attr_name)
297
+ previous_changes.include?(attr_name)
298
+ end
299
+
270
300
  # Handles <tt>*_change</tt> for +method_missing+.
271
301
  def attribute_change(attr)
272
- [attribute_was(attr), _read_attribute(attr)] if attribute_changed?(attr)
302
+ [changed_attributes[attr], _read_attribute(attr)] if attribute_changed?(attr)
273
303
  end
274
304
 
275
305
  # Handles <tt>*_previous_change</tt> for +method_missing+.
276
306
  def attribute_previous_change(attr)
277
- mutations_before_last_save.change_to_attribute(attr)
307
+ previous_changes[attr] if attribute_previously_changed?(attr)
278
308
  end
279
309
 
280
310
  # Handles <tt>*_will_change!</tt> for +method_missing+.
281
311
  def attribute_will_change!(attr)
282
- attr = attr.to_s
283
- mutations_from_database.force_change(attr).tap do
284
- @attributes[attr] if defined?(@_pseudo_attributes)
312
+ unless attribute_changed?(attr)
313
+ begin
314
+ value = _read_attribute(attr)
315
+ value = value.duplicable? ? value.clone : value
316
+ rescue TypeError, NoMethodError
317
+ end
318
+
319
+ set_attribute_was(attr, value)
285
320
  end
321
+ mutations_from_database.force_change(attr)
286
322
  end
287
323
 
288
324
  # Handles <tt>restore_*!</tt> for +method_missing+.
289
325
  def restore_attribute!(attr)
290
326
  if attribute_changed?(attr)
291
- __send__("#{attr}=", attribute_was(attr))
327
+ __send__("#{attr}=", changed_attributes[attr])
292
328
  clear_attribute_changes([attr])
293
329
  end
294
330
  end
295
331
 
296
- def _prepare_changes
297
- if defined?(@_pseudo_attributes)
298
- changed.each do |attr|
299
- @attributes.write_from_user(attr, _read_attribute(attr))
300
- end
301
- end
332
+ def attributes_changed_by_setter
333
+ @attributes_changed_by_setter ||= ActiveSupport::HashWithIndifferentAccess.new
302
334
  end
303
335
 
304
- def _clone_attribute(attr)
305
- value = _read_attribute(attr)
306
- value.duplicable? ? value.clone : value
307
- rescue TypeError, NoMethodError
308
- value
336
+ # Force an attribute to have a particular "before" value
337
+ def set_attribute_was(attr, old_value)
338
+ attributes_changed_by_setter[attr] = old_value
309
339
  end
310
340
  end
311
341
  end
@@ -10,7 +10,7 @@ module ActiveModel
10
10
  MAJOR = 5
11
11
  MINOR = 2
12
12
  TINY = 0
13
- PRE = "rc1"
13
+ PRE = "rc2"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -179,7 +179,7 @@ module ActiveModel
179
179
  return unless includes = options[:include]
180
180
 
181
181
  unless includes.is_a?(Hash)
182
- includes = Hash[Array(includes).map { |n| n.is_a?(Hash) ? n.to_a.first : [n, {}] }]
182
+ includes = Hash[Array(includes).flat_map { |n| n.is_a?(Hash) ? n.to_a : [[n, {}]] }]
183
183
  end
184
184
 
185
185
  includes.each do |association, opts|
@@ -42,7 +42,7 @@ module ActiveModel
42
42
  end
43
43
 
44
44
  def new_date(year, mon, mday)
45
- if year && year != 0
45
+ unless year.nil? || (year == 0 && mon == 0 && mday == 0)
46
46
  ::Date.new(year, mon, mday) rescue nil
47
47
  end
48
48
  end
@@ -28,14 +28,10 @@ module ActiveModel
28
28
  private
29
29
 
30
30
  def cast_value(value)
31
- return value unless value.is_a?(::String)
31
+ return apply_seconds_precision(value) unless value.is_a?(::String)
32
32
  return if value.empty?
33
33
 
34
- if value.start_with?("2000-01-01")
35
- dummy_time_value = value
36
- else
37
- dummy_time_value = "2000-01-01 #{value}"
38
- end
34
+ dummy_time_value = value.sub(/\A(\d\d\d\d-\d\d-\d\d |)/, "2000-01-01 ")
39
35
 
40
36
  fast_string_to_time(dummy_time_value) || begin
41
37
  time_hash = ::Date._parse(dummy_time_value)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0.rc1
4
+ version: 5.2.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-30 00:00:00.000000000 Z
11
+ date: 2018-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 5.2.0.rc1
19
+ version: 5.2.0.rc2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 5.2.0.rc1
26
+ version: 5.2.0.rc2
27
27
  description: A toolkit for building modeling frameworks like Active Record. Rich support
28
28
  for attributes, callbacks, validations, serialization, internationalization, and
29
29
  testing.
@@ -100,8 +100,8 @@ homepage: http://rubyonrails.org
100
100
  licenses:
101
101
  - MIT
102
102
  metadata:
103
- source_code_uri: https://github.com/rails/rails/tree/v5.2.0.rc1/activemodel
104
- changelog_uri: https://github.com/rails/rails/blob/v5.2.0.rc1/activemodel/CHANGELOG.md
103
+ source_code_uri: https://github.com/rails/rails/tree/v5.2.0.rc2/activemodel
104
+ changelog_uri: https://github.com/rails/rails/blob/v5.2.0.rc2/activemodel/CHANGELOG.md
105
105
  post_install_message:
106
106
  rdoc_options: []
107
107
  require_paths:
@@ -118,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
118
  version: 1.3.1
119
119
  requirements: []
120
120
  rubyforge_project:
121
- rubygems_version: 2.7.3
121
+ rubygems_version: 2.7.6
122
122
  signing_key:
123
123
  specification_version: 4
124
124
  summary: A toolkit for building modeling frameworks (part of Rails).