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.
- checksums.yaml +5 -5
- data/.rubocop_todo.yml +50 -43
- data/.travis.yml +2 -1
- data/CHANGELOG.md +33 -0
- data/CONTRIBUTING.md +4 -4
- data/Gemfile +16 -11
- data/LICENSE.txt +1 -1
- data/README.md +97 -20
- data/RELEASING.md +67 -0
- data/Rakefile +1 -1
- data/UPGRADING.md +53 -0
- data/lib/mongoid/history.rb +33 -8
- data/lib/mongoid/history/attributes/base.rb +2 -2
- data/lib/mongoid/history/attributes/create.rb +6 -11
- data/lib/mongoid/history/attributes/destroy.rb +9 -9
- data/lib/mongoid/history/attributes/update.rb +82 -21
- data/lib/mongoid/history/options.rb +60 -67
- data/lib/mongoid/history/trackable.rb +173 -91
- data/lib/mongoid/history/tracker.rb +22 -13
- data/lib/mongoid/history/version.rb +1 -1
- data/mongoid-history.gemspec +1 -1
- data/perf/benchmark_modified_attributes_for_create.rb +65 -0
- data/perf/gc_suite.rb +21 -0
- data/spec/integration/embedded_in_polymorphic_spec.rb +26 -49
- data/spec/integration/integration_spec.rb +186 -146
- data/spec/integration/multi_relation_spec.rb +14 -20
- data/spec/integration/multiple_trackers_spec.rb +68 -0
- data/spec/integration/nested_embedded_documents_spec.rb +31 -51
- data/spec/integration/nested_embedded_documents_tracked_in_parent_spec.rb +124 -0
- data/spec/integration/nested_embedded_polymorphic_documents_spec.rb +64 -76
- data/spec/integration/subclasses_spec.rb +24 -6
- data/spec/integration/track_history_order_spec.rb +84 -0
- data/spec/integration/validation_failure_spec.rb +76 -0
- data/spec/spec_helper.rb +6 -1
- data/spec/support/mongoid_history.rb +0 -1
- data/spec/unit/attributes/base_spec.rb +17 -26
- data/spec/unit/attributes/create_spec.rb +152 -125
- data/spec/unit/attributes/destroy_spec.rb +69 -59
- data/spec/unit/attributes/update_spec.rb +165 -33
- data/spec/unit/callback_options_spec.rb +165 -0
- data/spec/unit/embedded_methods_spec.rb +42 -24
- data/spec/unit/history_spec.rb +33 -10
- data/spec/unit/my_instance_methods_spec.rb +191 -121
- data/spec/unit/options_spec.rb +121 -82
- data/spec/unit/singleton_methods_spec.rb +168 -100
- data/spec/unit/trackable_spec.rb +549 -148
- data/spec/unit/tracker_spec.rb +81 -54
- metadata +19 -6
@@ -5,16 +5,18 @@ module Mongoid
|
|
5
5
|
|
6
6
|
module ClassMethods
|
7
7
|
def track_history(options = {})
|
8
|
-
extend
|
8
|
+
extend RelationMethods
|
9
9
|
|
10
|
-
|
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
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
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
|
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
|
115
|
-
send(self.class.
|
132
|
+
def _get_relation(name)
|
133
|
+
send(self.class.relation_alias(name))
|
116
134
|
end
|
117
135
|
|
118
|
-
def
|
119
|
-
send("create_#{self.class.
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
199
|
+
elsif Mongoid::Compatibility::Version.mongoid6_or_older?
|
180
200
|
relation.class_name == node.relation_metadata.class_name.to_s &&
|
181
|
-
|
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,
|
258
|
-
o, m =
|
259
|
-
original
|
260
|
-
modified
|
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 =
|
275
|
-
|
276
|
-
|
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
|
283
|
-
#
|
350
|
+
module RelationMethods
|
351
|
+
# Returns a relation class for the given field.
|
284
352
|
#
|
285
|
-
# @param [ String | Symbol ]
|
353
|
+
# @param [ String | Symbol ] field The name of the field.
|
286
354
|
#
|
287
|
-
# @return [
|
288
|
-
def
|
289
|
-
|
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
|
-
#
|
361
|
+
# Indicates whether there is an Embedded::One relation for the given embedded field.
|
293
362
|
#
|
294
|
-
# @param [ String ]
|
363
|
+
# @param [ String | Symbol ] embed The name of the embedded field.
|
295
364
|
#
|
296
|
-
# @return [
|
297
|
-
def
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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 ]
|
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?(
|
313
|
-
relation_of(
|
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
|
-
#
|
387
|
+
# Retrieves the database representation of an embedded field name, in case the :store_as option is used.
|
317
388
|
#
|
318
|
-
# @param [ String ]
|
389
|
+
# @param [ String | Symbol ] embed The name or alias of the embedded field.
|
319
390
|
#
|
320
|
-
# @return [
|
321
|
-
def
|
322
|
-
|
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
|
-
|
396
|
+
protected
|
397
|
+
|
398
|
+
# Return the reflected metadata for a relation.
|
332
399
|
#
|
333
|
-
# @param [ String
|
400
|
+
# @param [ String ] field The database field name for a relation.
|
334
401
|
#
|
335
|
-
# @return [
|
336
|
-
def
|
337
|
-
|
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
|
-
|
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
|
346
|
-
@
|
347
|
-
|
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 ||=
|
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
|
-
|
449
|
-
|
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
|
-
|
473
|
-
|
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 ||=
|
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
|
-
|
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
|
-
|
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
|
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.
|
184
|
+
trackable_parent._create_relation(name, localize_keys(original))
|
180
185
|
elsif trackable_parent.class.embeds_many?(name)
|
181
|
-
trackable_parent.
|
186
|
+
trackable_parent._get_relation(name).create!(localize_keys(original))
|
182
187
|
else
|
183
|
-
|
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.
|
209
|
+
doc._get_relation(name)
|
205
210
|
elsif doc.class.embeds_many?(name)
|
206
|
-
doc.
|
211
|
+
doc._get_relation(name).unscoped.where(_id: node['id']).first
|
207
212
|
else
|
208
|
-
|
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
|
219
|
-
|
220
|
-
|
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
|
|