mongoid-history 0.6.1 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop_todo.yml +50 -43
  3. data/.travis.yml +2 -1
  4. data/CHANGELOG.md +33 -0
  5. data/CONTRIBUTING.md +4 -4
  6. data/Gemfile +16 -11
  7. data/LICENSE.txt +1 -1
  8. data/README.md +97 -20
  9. data/RELEASING.md +67 -0
  10. data/Rakefile +1 -1
  11. data/UPGRADING.md +53 -0
  12. data/lib/mongoid/history.rb +33 -8
  13. data/lib/mongoid/history/attributes/base.rb +2 -2
  14. data/lib/mongoid/history/attributes/create.rb +6 -11
  15. data/lib/mongoid/history/attributes/destroy.rb +9 -9
  16. data/lib/mongoid/history/attributes/update.rb +82 -21
  17. data/lib/mongoid/history/options.rb +60 -67
  18. data/lib/mongoid/history/trackable.rb +173 -91
  19. data/lib/mongoid/history/tracker.rb +22 -13
  20. data/lib/mongoid/history/version.rb +1 -1
  21. data/mongoid-history.gemspec +1 -1
  22. data/perf/benchmark_modified_attributes_for_create.rb +65 -0
  23. data/perf/gc_suite.rb +21 -0
  24. data/spec/integration/embedded_in_polymorphic_spec.rb +26 -49
  25. data/spec/integration/integration_spec.rb +186 -146
  26. data/spec/integration/multi_relation_spec.rb +14 -20
  27. data/spec/integration/multiple_trackers_spec.rb +68 -0
  28. data/spec/integration/nested_embedded_documents_spec.rb +31 -51
  29. data/spec/integration/nested_embedded_documents_tracked_in_parent_spec.rb +124 -0
  30. data/spec/integration/nested_embedded_polymorphic_documents_spec.rb +64 -76
  31. data/spec/integration/subclasses_spec.rb +24 -6
  32. data/spec/integration/track_history_order_spec.rb +84 -0
  33. data/spec/integration/validation_failure_spec.rb +76 -0
  34. data/spec/spec_helper.rb +6 -1
  35. data/spec/support/mongoid_history.rb +0 -1
  36. data/spec/unit/attributes/base_spec.rb +17 -26
  37. data/spec/unit/attributes/create_spec.rb +152 -125
  38. data/spec/unit/attributes/destroy_spec.rb +69 -59
  39. data/spec/unit/attributes/update_spec.rb +165 -33
  40. data/spec/unit/callback_options_spec.rb +165 -0
  41. data/spec/unit/embedded_methods_spec.rb +42 -24
  42. data/spec/unit/history_spec.rb +33 -10
  43. data/spec/unit/my_instance_methods_spec.rb +191 -121
  44. data/spec/unit/options_spec.rb +121 -82
  45. data/spec/unit/singleton_methods_spec.rb +168 -100
  46. data/spec/unit/trackable_spec.rb +549 -148
  47. data/spec/unit/tracker_spec.rb +81 -54
  48. metadata +19 -6
@@ -5,16 +5,18 @@ module Mongoid
5
5
 
6
6
  module ClassMethods
7
7
  def track_history(options = {})
8
- extend EmbeddedMethods
8
+ extend RelationMethods
9
9
 
10
- options_parser = Mongoid::History::Options.new(self)
11
- options = options_parser.parse(options)
10
+ history_options = Mongoid::History::Options.new(self, options)
12
11
 
13
- field options[:version_field].to_sym, type: Integer
12
+ field history_options.options[:version_field].to_sym, type: Integer
14
13
 
15
- belongs_to_modifier_options = { class_name: Mongoid::History.modifier_class_name }
16
- belongs_to_modifier_options[:inverse_of] = options[:modifier_field_inverse_of] if options.key?(:modifier_field_inverse_of)
17
- belongs_to options[:modifier_field].to_sym, belongs_to_modifier_options
14
+ unless history_options.options[:modifier_field].nil?
15
+ belongs_to_modifier_options = { class_name: Mongoid::History.modifier_class_name }
16
+ belongs_to_modifier_options[:inverse_of] = history_options.options[:modifier_field_inverse_of] if history_options.options.key?(:modifier_field_inverse_of)
17
+ belongs_to_modifier_options[:optional] = true if history_options.options[:modifier_field_optional] && Mongoid::Compatibility::Version.mongoid6_or_newer?
18
+ belongs_to history_options.options[:modifier_field].to_sym, belongs_to_modifier_options
19
+ end
18
20
 
19
21
  include MyInstanceMethods
20
22
  extend SingletonMethods
@@ -22,12 +24,16 @@ module Mongoid
22
24
  delegate :history_trackable_options, to: 'self.class'
23
25
  delegate :track_history?, to: 'self.class'
24
26
 
25
- before_update :track_update if options[:track_update]
26
- before_create :track_create if options[:track_create]
27
- before_destroy :track_destroy if options[:track_destroy]
27
+ callback_options = history_options.options.slice(:if, :unless)
28
+ around_update :track_update, **callback_options if history_options.options[:track_update]
29
+ around_create :track_create, **callback_options if history_options.options[:track_create]
30
+ around_destroy :track_destroy, **callback_options if history_options.options[:track_destroy]
31
+
32
+ unless respond_to? :mongoid_history_options
33
+ class_attribute :mongoid_history_options, instance_accessor: false
34
+ end
28
35
 
29
- Mongoid::History.trackable_class_options ||= {}
30
- Mongoid::History.trackable_class_options[options_parser.scope] = options
36
+ self.mongoid_history_options = history_options
31
37
  end
32
38
 
33
39
  def history_settings(options = {})
@@ -46,13 +52,25 @@ module Mongoid
46
52
  Mongoid::Compatibility::Version.mongoid3? || (self < Mongoid::Attributes::Dynamic).present?
47
53
  end
48
54
 
49
- def disable_tracking(&_block)
55
+ def disable_tracking
56
+ original_flag = Mongoid::History.store[track_history_flag]
50
57
  Mongoid::History.store[track_history_flag] = false
51
- yield
58
+ yield if block_given?
52
59
  ensure
60
+ Mongoid::History.store[track_history_flag] = original_flag if block_given?
61
+ end
62
+
63
+ def enable_tracking
64
+ original_flag = Mongoid::History.store[track_history_flag]
53
65
  Mongoid::History.store[track_history_flag] = true
66
+ yield if block_given?
67
+ ensure
68
+ Mongoid::History.store[track_history_flag] = original_flag if block_given?
54
69
  end
55
70
 
71
+ alias disable_tracking! disable_tracking
72
+ alias enable_tracking! enable_tracking
73
+
56
74
  def track_history_flag
57
75
  "mongoid_history_#{name.underscore}_trackable_enabled".to_sym
58
76
  end
@@ -111,12 +129,12 @@ module Mongoid
111
129
  end
112
130
  end
113
131
 
114
- def get_embedded(name)
115
- send(self.class.embedded_alias(name))
132
+ def _get_relation(name)
133
+ send(self.class.relation_alias(name))
116
134
  end
117
135
 
118
- def create_embedded(name, value)
119
- send("create_#{self.class.embedded_alias(name)}!", value)
136
+ def _create_relation(name, value)
137
+ send("create_#{self.class.relation_alias(name)}!", value)
120
138
  end
121
139
 
122
140
  private
@@ -131,7 +149,7 @@ module Mongoid
131
149
  elsif options[:last]
132
150
  versions = history_tracks.limit(options[:last])
133
151
  else
134
- fail 'Invalid options, please specify (:from / :to) keys or :last key.'
152
+ raise 'Invalid options, please specify (:from / :to) keys or :last key.'
135
153
  end
136
154
  else
137
155
  options_or_version = options_or_version.to_a if options_or_version.is_a?(Range)
@@ -154,8 +172,10 @@ module Mongoid
154
172
  scope = _parent.collection_name.to_s.singularize.to_sym if scope.is_a?(Array)
155
173
  if Mongoid::Compatibility::Version.mongoid3?
156
174
  scope = metadata.inverse_class_name.tableize.singularize.to_sym if metadata.present? && scope == metadata.as
157
- else
175
+ elsif Mongoid::Compatibility::Version.mongoid6_or_older?
158
176
  scope = relation_metadata.inverse_class_name.tableize.singularize.to_sym if relation_metadata.present? && scope == relation_metadata.as
177
+ elsif Mongoid::Compatibility::Version.mongoid7_or_newer?
178
+ scope = _association.inverse_class_name.tableize.singularize.to_sym if _association.present? && scope == _association.as
159
179
  end
160
180
  end
161
181
 
@@ -170,15 +190,18 @@ module Mongoid
170
190
 
171
191
  def association_hash(node = self)
172
192
  # We prefer to look up associations through the parent record because
173
- # we're assured, through the object creation, it'll exist. Whereas we're not guarenteed
193
+ # we're assured, through the object creation, it'll exist. Whereas we're not guaranteed
174
194
  # the child to parent (embedded_in, belongs_to) relation will be defined
175
195
  if node._parent
176
196
  meta = node._parent.relations.values.find do |relation|
177
197
  if Mongoid::Compatibility::Version.mongoid3?
178
198
  relation.class_name == node.metadata.class_name.to_s && relation.name == node.metadata.name
179
- else
199
+ elsif Mongoid::Compatibility::Version.mongoid6_or_older?
180
200
  relation.class_name == node.relation_metadata.class_name.to_s &&
181
- relation.name == node.relation_metadata.name
201
+ relation.name == node.relation_metadata.name
202
+ elsif Mongoid::Compatibility::Version.mongoid7_or_newer?
203
+ relation.class_name == node._association.class_name.to_s &&
204
+ relation.name == node._association.name
182
205
  end
183
206
  end
184
207
  end
@@ -219,11 +242,12 @@ module Mongoid
219
242
  def history_tracker_attributes(action)
220
243
  return @history_tracker_attributes if @history_tracker_attributes
221
244
 
245
+ modifier_field = history_trackable_options[:modifier_field]
222
246
  @history_tracker_attributes = {
223
247
  association_chain: traverse_association_chain,
224
- scope: related_scope,
225
- modifier: send(history_trackable_options[:modifier_field])
248
+ scope: related_scope
226
249
  }
250
+ @history_tracker_attributes[:modifier] = send(modifier_field) if modifier_field
227
251
 
228
252
  original, modified = transform_changes(modified_attributes_for_action(action))
229
253
 
@@ -232,16 +256,16 @@ module Mongoid
232
256
  @history_tracker_attributes
233
257
  end
234
258
 
235
- def track_create
236
- track_history_for_action(:create)
259
+ def track_create(&block)
260
+ track_history_for_action(:create, &block)
237
261
  end
238
262
 
239
- def track_update
240
- track_history_for_action(:update)
263
+ def track_update(&block)
264
+ track_history_for_action(:update, &block)
241
265
  end
242
266
 
243
- def track_destroy
244
- track_history_for_action(:destroy) unless destroyed?
267
+ def track_destroy(&block)
268
+ track_history_for_action(:destroy, &block) unless destroyed?
245
269
  end
246
270
 
247
271
  def clear_trackable_memoization
@@ -251,18 +275,49 @@ module Mongoid
251
275
  @history_tracks = nil
252
276
  end
253
277
 
278
+ # Transform hash of pair of changes into an `original` and `modified` hash
279
+ # Nested document keys (key name with dots) are expanded
280
+ #
281
+ # @param [Hash<Array>] changes
282
+ #
283
+ # @return [Array<Hash<?>,Hash<?>>] <description>
254
284
  def transform_changes(changes)
255
285
  original = {}
256
286
  modified = {}
257
- changes.each_pair do |k, v|
258
- o, m = v
259
- original[k] = o unless o.nil?
260
- modified[k] = m unless m.nil?
287
+ changes.each_pair do |k, modification_pair|
288
+ o, m = modification_pair
289
+ original.deep_merge!(expand_nested_document_key_value(k, o)) unless o.nil?
290
+ modified.deep_merge!(expand_nested_document_key_value(k, m)) unless m.nil?
261
291
  end
262
292
 
263
293
  [original, modified]
264
294
  end
265
295
 
296
+ # Handle nested document tracking of changes
297
+ #
298
+ # @example
299
+ #
300
+ # expand_nested_document_key('embedded.document.changed_field', 'old'])
301
+ # #=> { 'embedded' => {'document' => { 'changed_field' => 'old' }}}
302
+ #
303
+ # @param [String] document_key key with dots
304
+ # @param [?] value
305
+ #
306
+ # @return [Hash<String, ?>]
307
+ def expand_nested_document_key_value(document_key, value)
308
+ expanded_key = value
309
+ document_key.to_s.split('.').reverse.each do |key|
310
+ expanded_key = { key => expanded_key }
311
+ end
312
+ expanded_key
313
+ end
314
+
315
+ def increment_current_version
316
+ current_version = (send(history_trackable_options[:version_field]) || 0) + 1
317
+ send("#{history_trackable_options[:version_field]}=", current_version)
318
+ current_version
319
+ end
320
+
266
321
  protected
267
322
 
268
323
  def track_history_for_action?(action)
@@ -271,88 +326,106 @@ module Mongoid
271
326
 
272
327
  def track_history_for_action(action)
273
328
  if track_history_for_action?(action)
274
- current_version = (send(history_trackable_options[:version_field]) || 0) + 1
275
- send("#{history_trackable_options[:version_field]}=", current_version)
276
- self.class.tracker_class.create!(history_tracker_attributes(action.to_sym).merge(version: current_version, action: action.to_s, trackable: self))
329
+ current_version = increment_current_version
330
+ last_track = self.class.tracker_class.create!(
331
+ history_tracker_attributes(action.to_sym)
332
+ .merge(version: current_version, action: action.to_s, trackable: self)
333
+ )
277
334
  end
335
+
278
336
  clear_trackable_memoization
337
+
338
+ begin
339
+ yield
340
+ rescue => e
341
+ if track_history_for_action?(action)
342
+ send("#{history_trackable_options[:version_field]}=", current_version - 1)
343
+ last_track.destroy
344
+ end
345
+ raise e
346
+ end
279
347
  end
280
348
  end
281
349
 
282
- module EmbeddedMethods
283
- # Indicates whether there is an Embedded::One relation for the given embedded field.
350
+ module RelationMethods
351
+ # Returns a relation class for the given field.
284
352
  #
285
- # @param [ String | Symbol ] embed The name of the embedded field
353
+ # @param [ String | Symbol ] field The name of the field.
286
354
  #
287
- # @return [ Boolean ] true if there is an Embedded::One relation for the given embedded field
288
- def embeds_one?(embed)
289
- relation_of(embed) == Mongoid::Relations::Embedded::One
355
+ # @return [ nil | Constant ] Class being related.
356
+ def relation_class_of(field)
357
+ meta = meta_of(field)
358
+ return meta.class_name.constantize if meta
290
359
  end
291
360
 
292
- # Return the class for embeds_one relation
361
+ # Indicates whether there is an Embedded::One relation for the given embedded field.
293
362
  #
294
- # @param [ String ] field The database field name for embedded relation
363
+ # @param [ String | Symbol ] embed The name of the embedded field.
295
364
  #
296
- # @return [ nil | Constant ]
297
- def embeds_one_class(field)
298
- @embeds_one_class ||= {}
299
- return @embeds_one_class[field] if @embeds_one_class.key?(field)
300
- field_alias = aliased_fields.key(field)
301
- relation = relations
302
- .select { |_, v| v.relation == Mongoid::Relations::Embedded::One }
303
- .detect { |rel_k, _| rel_k == field_alias }
304
- @embeds_one_class[field] = relation && relation.last.class_name.constantize
365
+ # @return [ Boolean ] true if there is an Embedded::One relation for the given embedded field.
366
+ def embeds_one?(field)
367
+ relation_of(field) == if Mongoid::Compatibility::Version.mongoid7_or_newer?
368
+ Mongoid::Association::Embedded::EmbedsOne::Proxy
369
+ else
370
+ Mongoid::Relations::Embedded::One
371
+ end
305
372
  end
306
373
 
307
374
  # Indicates whether there is an Embedded::Many relation for the given embedded field.
308
375
  #
309
- # @param [ String | Symbol ] embed The name of the embedded field
376
+ # @param [ String | Symbol ] field The name of the embedded field.
310
377
  #
311
- # @return [ Boolean ] true if there is an Embedded::Many relation for the given embedded field
312
- def embeds_many?(embed)
313
- relation_of(embed) == Mongoid::Relations::Embedded::Many
378
+ # @return [ Boolean ] true if there is an Embedded::Many relation for the given embedded field.
379
+ def embeds_many?(field)
380
+ relation_of(field) == if Mongoid::Compatibility::Version.mongoid7_or_newer?
381
+ Mongoid::Association::Embedded::EmbedsMany::Proxy
382
+ else
383
+ Mongoid::Relations::Embedded::Many
384
+ end
314
385
  end
315
386
 
316
- # Return the class for embeds_many relation
387
+ # Retrieves the database representation of an embedded field name, in case the :store_as option is used.
317
388
  #
318
- # @param [ String ] field The database field name for embedded relation
389
+ # @param [ String | Symbol ] embed The name or alias of the embedded field.
319
390
  #
320
- # @return [ nil | Constant ]
321
- def embeds_many_class(field)
322
- @embeds_many_class ||= {}
323
- return @embeds_many_class[field] if @embeds_many_class.key?(field)
324
- field_alias = aliased_fields.key(field)
325
- relation = relations
326
- .select { |_, v| v.relation == Mongoid::Relations::Embedded::Many }
327
- .detect { |rel_k, _| rel_k == field_alias }
328
- @embeds_many_class[field] = relation && relation.last.class_name.constantize
391
+ # @return [ String ] The database name of the embedded field.
392
+ def relation_alias(embed)
393
+ relation_aliases[embed]
329
394
  end
330
395
 
331
- # Retrieves the database representation of an embedded field name, in case the :store_as option is used.
396
+ protected
397
+
398
+ # Return the reflected metadata for a relation.
332
399
  #
333
- # @param [ String | Symbol ] embed The name or alias of the embedded field
400
+ # @param [ String ] field The database field name for a relation.
334
401
  #
335
- # @return [ String ] the database name of the embedded field
336
- def embedded_alias(embed)
337
- embedded_aliases[embed]
402
+ # @return [ nil | Mongoid::Relations::Metadata ]
403
+ def meta_of(field)
404
+ @meta_of ||= {}
405
+ return @meta_of[field] if @meta_of.key?(field)
406
+ @meta_of[field] = reflect_on_association(relation_alias(field))
338
407
  end
339
408
 
340
- protected
409
+ # Returns a relation for the given field.
410
+ #
411
+ # @param [ String | Symbol ] field The name of the field.
412
+ #
413
+ # @return [ nil | Constant ] Type of relation.
414
+ def relation_of(field)
415
+ meta = meta_of(field)
416
+ meta ? meta.relation : nil
417
+ end
341
418
 
342
419
  # Retrieves the memoized hash of embedded aliases and their associated database representations.
343
420
  #
344
421
  # @return [ Hash < String, String > ] hash of embedded aliases (keys) to database representations (values)
345
- def embedded_aliases
346
- @embedded_aliases ||= relations.inject(HashWithIndifferentAccess.new) do |h, (k, v)|
347
- h[v[:store_as] || k] = k
422
+ def relation_aliases
423
+ @relation_aliases ||= relations.inject(HashWithIndifferentAccess.new) do |h, (k, v)|
424
+ store_as = Mongoid::Compatibility::Version.mongoid7_or_newer? ? v.store_as : v[:store_as]
425
+ h[store_as || k] = k
348
426
  h
349
427
  end
350
428
  end
351
-
352
- def relation_of(embed)
353
- meta = reflect_on_association(embedded_alias(embed))
354
- meta ? meta.relation : nil
355
- end
356
429
  end
357
430
 
358
431
  module SingletonMethods
@@ -414,7 +487,12 @@ module Mongoid
414
487
  #
415
488
  # @return [ Array < String > ] the list of reserved database field names
416
489
  def reserved_tracked_fields
417
- @reserved_tracked_fields ||= ['_id', history_trackable_options[:version_field].to_s, "#{history_trackable_options[:modifier_field]}_id"]
490
+ @reserved_tracked_fields ||= begin
491
+ fields = ['_id', history_trackable_options[:version_field].to_s]
492
+ modifier_field = history_trackable_options[:modifier_field]
493
+ fields << "#{modifier_field}_id" if modifier_field
494
+ fields
495
+ end
418
496
  end
419
497
 
420
498
  def field_formats
@@ -445,8 +523,8 @@ module Mongoid
445
523
  def tracked_embeds_one
446
524
  @tracked_embeds_one ||= begin
447
525
  reflect_on_all_associations(:embeds_one)
448
- .map(&:key)
449
- .select { |rel| history_trackable_options[:relations][:embeds_one].include? rel }
526
+ .map(&:key)
527
+ .select { |rel| history_trackable_options[:relations][:embeds_one].include? rel }
450
528
  end
451
529
  end
452
530
 
@@ -469,8 +547,8 @@ module Mongoid
469
547
  def tracked_embeds_many
470
548
  @tracked_embeds_many ||= begin
471
549
  reflect_on_all_associations(:embeds_many)
472
- .map(&:key)
473
- .select { |rel| history_trackable_options[:relations][:embeds_many].include? rel }
550
+ .map(&:key)
551
+ .select { |rel| history_trackable_options[:relations][:embeds_many].include? rel }
474
552
  end
475
553
  end
476
554
 
@@ -483,7 +561,7 @@ module Mongoid
483
561
  end
484
562
 
485
563
  def history_trackable_options
486
- @history_trackable_options ||= Mongoid::History.trackable_class_options[trackable_scope]
564
+ @history_trackable_options ||= mongoid_history_options.prepared
487
565
  end
488
566
 
489
567
  def clear_trackable_memoization
@@ -493,7 +571,11 @@ module Mongoid
493
571
  @tracked_fields = nil
494
572
  @tracked_embeds_one = nil
495
573
  @tracked_embeds_many = nil
496
- @obfuscated_fields = nil
574
+ end
575
+
576
+ def inherited(subclass)
577
+ super
578
+ subclass.mongoid_history_options = Mongoid::History::Options.new(subclass, mongoid_history_options.options)
497
579
  end
498
580
  end
499
581
  end
@@ -14,12 +14,16 @@ module Mongoid
14
14
  field :version, type: Integer
15
15
  field :action, type: String
16
16
  field :scope, type: String
17
- belongs_to :modifier, class_name: Mongoid::History.modifier_class_name
17
+ modifier_options = {
18
+ class_name: Mongoid::History.modifier_class_name
19
+ }
20
+ modifier_options[:optional] = true if Mongoid::Compatibility::Version.mongoid6_or_newer?
21
+ belongs_to :modifier, modifier_options
18
22
 
19
23
  index(scope: 1)
20
24
  index(association_chain: 1)
21
25
 
22
- Mongoid::History.tracker_class_name = name.tableize.singularize.to_sym
26
+ Mongoid::History.tracker_class_name ||= name.tableize.singularize.to_sym
23
27
  end
24
28
 
25
29
  def undo!(modifier = nil)
@@ -50,7 +54,7 @@ module Mongoid
50
54
  undo_hash = affected.easy_unmerge(modified)
51
55
  undo_hash.easy_merge!(original)
52
56
  modifier_field = trackable.history_trackable_options[:modifier_field]
53
- undo_hash[modifier_field] = modifier
57
+ undo_hash[modifier_field] = modifier if modifier_field
54
58
  (modified.keys - undo_hash.keys).each do |k|
55
59
  undo_hash[k] = nil
56
60
  end
@@ -61,7 +65,7 @@ module Mongoid
61
65
  redo_hash = affected.easy_unmerge(original)
62
66
  redo_hash.easy_merge!(modified)
63
67
  modifier_field = trackable.history_trackable_options[:modifier_field]
64
- redo_hash[modifier_field] = modifier
68
+ redo_hash[modifier_field] = modifier if modifier_field
65
69
  localize_keys(redo_hash)
66
70
  end
67
71
 
@@ -175,12 +179,13 @@ module Mongoid
175
179
 
176
180
  def create_on_parent
177
181
  name = association_chain.last['name']
182
+
178
183
  if trackable_parent.class.embeds_one?(name)
179
- trackable_parent.create_embedded(name, localize_keys(original))
184
+ trackable_parent._create_relation(name, localize_keys(original))
180
185
  elsif trackable_parent.class.embeds_many?(name)
181
- trackable_parent.get_embedded(name).create!(localize_keys(original))
186
+ trackable_parent._get_relation(name).create!(localize_keys(original))
182
187
  else
183
- fail 'This should never happen. Please report bug!'
188
+ raise 'This should never happen. Please report bug!'
184
189
  end
185
190
  end
186
191
 
@@ -201,11 +206,13 @@ module Mongoid
201
206
  klass = name.classify.constantize
202
207
  klass.unscoped.where(_id: node['id']).first
203
208
  elsif doc.class.embeds_one?(name)
204
- doc.get_embedded(name)
209
+ doc._get_relation(name)
205
210
  elsif doc.class.embeds_many?(name)
206
- doc.get_embedded(name).unscoped.where(_id: node['id']).first
211
+ doc._get_relation(name).unscoped.where(_id: node['id']).first
207
212
  else
208
- fail 'This should never happen. Please report bug.'
213
+ relation_klass = doc.class.relation_class_of(name) if doc
214
+ relation_klass ||= 'nil'
215
+ raise "Unexpected relation for field '#{name}': #{relation_klass}. This should never happen. Please report bug."
209
216
  end
210
217
  documents << doc
211
218
  break if chain.empty?
@@ -215,9 +222,11 @@ module Mongoid
215
222
 
216
223
  def localize_keys(hash)
217
224
  klass = association_chain.first['name'].constantize
218
- klass.localized_fields.keys.each do |name|
219
- hash["#{name}_translations"] = hash.delete(name) if hash[name].present?
220
- end if klass.respond_to?(:localized_fields)
225
+ if klass.respond_to?(:localized_fields)
226
+ klass.localized_fields.keys.each do |name|
227
+ hash["#{name}_translations"] = hash.delete(name) if hash[name].present?
228
+ end
229
+ end
221
230
  hash
222
231
  end
223
232