mongoid-history 0.8.1 → 0.8.2
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 +5 -5
- data/.rubocop_todo.yml +26 -25
- data/.travis.yml +1 -1
- data/CHANGELOG.md +7 -0
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/lib/mongoid/history.rb +11 -2
- data/lib/mongoid/history/attributes/update.rb +72 -13
- data/lib/mongoid/history/options.rb +11 -3
- data/lib/mongoid/history/trackable.rb +39 -8
- data/lib/mongoid/history/version.rb +1 -1
- data/spec/integration/integration_spec.rb +22 -0
- data/spec/integration/nested_embedded_documents_tracked_in_parent_spec.rb +124 -0
- data/spec/support/mongoid_history.rb +0 -1
- data/spec/unit/history_spec.rb +21 -0
- data/spec/unit/options_spec.rb +9 -0
- data/spec/unit/trackable_spec.rb +60 -8
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 84ee622b782d764b3a15ea31bfac94cbedf3fa023d8ae0302022562d6a5a6ec2
|
|
4
|
+
data.tar.gz: abf09c6ed9db7126b9d7754f42a0f1b00317919ad6744f0486b4d970601eb3f4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 484eb94fae5bba8b787ffda61403e65c95684f9e3a77c03daa56952e056c440d639d58d3a381760e7996ec1bec1415fe409f6688fab38ed24d6e0315f53c9369
|
|
7
|
+
data.tar.gz: f66b6abc4dcf17696bafea67faddbcd0b97f194e8b8b36c48f32461a31987b9867a6dbf204a8604a391654ebace4c94c76b4b745ac2511b74db8df26f886d54a
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on
|
|
3
|
+
# on 2019-06-09 13:41:12 +0200 using RuboCop version 0.60.0.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
|
|
9
9
|
# Offense count: 7
|
|
10
10
|
# Configuration parameters: Include.
|
|
11
|
-
# Include: **/Gemfile, **/gems.rb
|
|
11
|
+
# Include: **/*.gemfile, **/Gemfile, **/gems.rb
|
|
12
12
|
Bundler/DuplicatedGem:
|
|
13
13
|
Exclude:
|
|
14
14
|
- 'Gemfile'
|
|
15
15
|
|
|
16
16
|
# Offense count: 1
|
|
17
17
|
# Cop supports --auto-correct.
|
|
18
|
-
# Configuration parameters: EnforcedStyleAlignWith,
|
|
18
|
+
# Configuration parameters: EnforcedStyleAlignWith, AutoCorrect, Severity.
|
|
19
19
|
# SupportedStylesAlignWith: keyword, variable, start_of_line
|
|
20
|
-
|
|
20
|
+
Layout/EndAlignment:
|
|
21
21
|
Exclude:
|
|
22
22
|
- 'lib/mongoid/history/options.rb'
|
|
23
23
|
|
|
@@ -32,44 +32,47 @@ Lint/ParenthesesAsGroupedExpression:
|
|
|
32
32
|
- 'spec/integration/integration_spec.rb'
|
|
33
33
|
- 'spec/integration/nested_embedded_polymorphic_documents_spec.rb'
|
|
34
34
|
|
|
35
|
-
# Offense count:
|
|
35
|
+
# Offense count: 22
|
|
36
36
|
Metrics/AbcSize:
|
|
37
37
|
Max: 52
|
|
38
38
|
|
|
39
|
-
# Offense count:
|
|
39
|
+
# Offense count: 122
|
|
40
40
|
# Configuration parameters: CountComments, ExcludedMethods.
|
|
41
|
+
# ExcludedMethods: refine
|
|
41
42
|
Metrics/BlockLength:
|
|
42
|
-
Max:
|
|
43
|
+
Max: 837
|
|
43
44
|
|
|
44
45
|
# Offense count: 1
|
|
45
46
|
# Configuration parameters: CountComments.
|
|
46
47
|
Metrics/ClassLength:
|
|
47
|
-
Max:
|
|
48
|
+
Max: 125
|
|
48
49
|
|
|
49
50
|
# Offense count: 6
|
|
50
51
|
Metrics/CyclomaticComplexity:
|
|
51
52
|
Max: 13
|
|
52
53
|
|
|
53
|
-
# Offense count:
|
|
54
|
-
# Configuration parameters:
|
|
55
|
-
# URISchemes: http, https
|
|
56
|
-
Metrics/LineLength:
|
|
57
|
-
Max: 688
|
|
58
|
-
|
|
59
|
-
# Offense count: 15
|
|
60
|
-
# Configuration parameters: CountComments.
|
|
54
|
+
# Offense count: 17
|
|
55
|
+
# Configuration parameters: CountComments, ExcludedMethods.
|
|
61
56
|
Metrics/MethodLength:
|
|
62
57
|
Max: 23
|
|
63
58
|
|
|
64
59
|
# Offense count: 2
|
|
65
60
|
# Configuration parameters: CountComments.
|
|
66
61
|
Metrics/ModuleLength:
|
|
67
|
-
Max:
|
|
62
|
+
Max: 191
|
|
68
63
|
|
|
69
64
|
# Offense count: 6
|
|
70
65
|
Metrics/PerceivedComplexity:
|
|
71
66
|
Max: 15
|
|
72
67
|
|
|
68
|
+
# Offense count: 1
|
|
69
|
+
# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms.
|
|
70
|
+
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
|
|
71
|
+
Naming/FileName:
|
|
72
|
+
Exclude:
|
|
73
|
+
- 'Dangerfile'
|
|
74
|
+
- 'lib/mongoid-history.rb'
|
|
75
|
+
|
|
73
76
|
# Offense count: 12
|
|
74
77
|
Style/Documentation:
|
|
75
78
|
Exclude:
|
|
@@ -91,15 +94,13 @@ Style/EachWithObject:
|
|
|
91
94
|
- 'lib/mongoid/history/trackable.rb'
|
|
92
95
|
- 'lib/mongoid/history/tracker.rb'
|
|
93
96
|
|
|
94
|
-
# Offense count: 2
|
|
95
|
-
# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms.
|
|
96
|
-
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
|
|
97
|
-
Style/FileName:
|
|
98
|
-
Exclude:
|
|
99
|
-
- 'Dangerfile'
|
|
100
|
-
- 'lib/mongoid-history.rb'
|
|
101
|
-
|
|
102
97
|
# Offense count: 1
|
|
103
98
|
Style/MultilineBlockChain:
|
|
104
99
|
Exclude:
|
|
105
100
|
- 'lib/mongoid/history/tracker.rb'
|
|
101
|
+
|
|
102
|
+
# Offense count: 404
|
|
103
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
|
104
|
+
# URISchemes: http, https
|
|
105
|
+
Metrics/LineLength:
|
|
106
|
+
Max: 688
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
### 0.8.2 (2019/12/02)
|
|
2
|
+
|
|
3
|
+
* [#233](https://github.com/mongoid/mongoid-history/pull/233): Bug fix-Track ALL embedded relations when used with fields and filtered attributes on embedded objects - [@jagdeepsingh](https://github.com/jagdeepsingh).
|
|
4
|
+
* [#232](https://github.com/mongoid/mongoid-history/pull/232): Bug/187 track changes from embedded documents (not deeply nested) - [@Startouf](https://github.com/Startouf).
|
|
5
|
+
* [#227](https://github.com/mongoid/mongoid-history/pull/227): Store options in inheritable class attributes - [@jnfeinstein](https://github.com/jnfeinstein).
|
|
6
|
+
* [#229](https://github.com/mongoid/mongoid-history/pull/229), [#225](https://github.com/mongoid/mongoid-history/pull/225): Fixed inheritance of `history_trackable_options` - [@jnfeinstein](https://github.com/jnfeinstein).
|
|
7
|
+
|
|
1
8
|
### 0.8.1 (2018/06/28)
|
|
2
9
|
|
|
3
10
|
* [#221](https://github.com/mongoid/mongoid-history/pull/221): Mongoid 7 support - [@dblock](https://github.com/dblock).
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -580,6 +580,6 @@ You're encouraged to contribute to this library. See [CONTRIBUTING](CONTRIBUTING
|
|
|
580
580
|
Copyright
|
|
581
581
|
---------
|
|
582
582
|
|
|
583
|
-
Copyright (c) 2011-
|
|
583
|
+
Copyright (c) 2011-2018 Aaron Qian and Contributors.
|
|
584
584
|
|
|
585
585
|
MIT License. See [LICENSE.txt](LICENSE.txt) for further details.
|
data/lib/mongoid/history.rb
CHANGED
|
@@ -15,7 +15,6 @@ module Mongoid
|
|
|
15
15
|
|
|
16
16
|
class << self
|
|
17
17
|
attr_accessor :tracker_class_name
|
|
18
|
-
attr_accessor :trackable_class_options
|
|
19
18
|
attr_accessor :trackable_settings
|
|
20
19
|
attr_accessor :modifier_class_name
|
|
21
20
|
attr_accessor :current_user_method
|
|
@@ -45,9 +44,19 @@ module Mongoid
|
|
|
45
44
|
|
|
46
45
|
def reset!
|
|
47
46
|
Mongoid::History.modifier_class_name = 'User'
|
|
48
|
-
Mongoid::History.trackable_class_options = {}
|
|
49
47
|
Mongoid::History.trackable_settings = {}
|
|
50
48
|
Mongoid::History.current_user_method ||= :current_user
|
|
49
|
+
|
|
50
|
+
Mongoid.models.each do |model|
|
|
51
|
+
next unless model.included_modules.include? Mongoid::History::Trackable
|
|
52
|
+
|
|
53
|
+
model.singleton_class.class_eval do
|
|
54
|
+
# Inverse of class_attribute
|
|
55
|
+
%i[mongoid_history_options
|
|
56
|
+
mongoid_history_options=
|
|
57
|
+
mongoid_history_options?].each { |m| remove_possible_method(m) }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
51
60
|
end
|
|
52
61
|
end
|
|
53
62
|
end
|
|
@@ -2,33 +2,91 @@ module Mongoid
|
|
|
2
2
|
module History
|
|
3
3
|
module Attributes
|
|
4
4
|
class Update < ::Mongoid::History::Attributes::Base
|
|
5
|
+
# @example when both an attribute `foo` and a child's attribute `nested_bar.baz` are changed
|
|
6
|
+
#
|
|
7
|
+
# {
|
|
8
|
+
# 'foo' => ['foo_before_changes', 'foo_after_changes']
|
|
9
|
+
# 'nested_bar.baz' => ['nested_bar_baz_before_changes', 'nested_bar_baz_after_changes']
|
|
10
|
+
# }
|
|
11
|
+
# }
|
|
12
|
+
#
|
|
13
|
+
# @return [Hash<String, Array<(?,?)>>] Hash of changes
|
|
5
14
|
def attributes
|
|
6
|
-
|
|
15
|
+
changes_from_parent.deep_merge(changes_from_children)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def changes_from_parent
|
|
21
|
+
parent_changes = {}
|
|
7
22
|
changes.each do |k, v|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
23
|
+
change_value = begin
|
|
24
|
+
if trackable_class.tracked_embeds_one?(k)
|
|
25
|
+
embeds_one_changes_from_parent(k, v)
|
|
26
|
+
elsif trackable_class.tracked_embeds_many?(k)
|
|
27
|
+
embeds_many_changes_from_parent(k, v)
|
|
28
|
+
elsif trackable_class.tracked?(k, :update)
|
|
29
|
+
{ k => format_field(k, v) } unless v.all?(&:blank?)
|
|
30
|
+
end
|
|
14
31
|
end
|
|
32
|
+
parent_changes.merge!(change_value) if change_value.present?
|
|
15
33
|
end
|
|
16
|
-
|
|
34
|
+
parent_changes
|
|
17
35
|
end
|
|
18
36
|
|
|
19
|
-
|
|
37
|
+
def changes_from_children
|
|
38
|
+
embeds_one_changes_from_embedded_documents
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Retrieve the list of changes applied directly to the nested documents
|
|
42
|
+
#
|
|
43
|
+
# @example when a child's name is changed from "todd" to "mario"
|
|
44
|
+
#
|
|
45
|
+
# child = Child.new(name: 'todd')
|
|
46
|
+
# Parent.create(child: child)
|
|
47
|
+
# child.name = "Mario"
|
|
48
|
+
#
|
|
49
|
+
# embeds_one_changes_from_embedded_documents # when called from "Parent"
|
|
50
|
+
# # => { "child.name"=>["todd", "mario"] }
|
|
51
|
+
#
|
|
52
|
+
# @return [Hash<String, Array<(?,?)>] changes of embeds_ones from embedded documents
|
|
53
|
+
def embeds_one_changes_from_embedded_documents
|
|
54
|
+
embedded_doc_changes = {}
|
|
55
|
+
trackable_class.tracked_embeds_one.each do |rel|
|
|
56
|
+
rel_class = trackable_class.relation_class_of(rel)
|
|
57
|
+
paranoia_field = Mongoid::History.trackable_class_settings(rel_class)[:paranoia_field]
|
|
58
|
+
paranoia_field = rel_class.aliased_fields.key(paranoia_field) || paranoia_field
|
|
59
|
+
rel = aliased_fields.key(rel) || rel
|
|
60
|
+
obj = trackable.send(rel)
|
|
61
|
+
next if !obj || (obj.respond_to?(paranoia_field) && obj.public_send(paranoia_field).present?)
|
|
20
62
|
|
|
21
|
-
|
|
63
|
+
obj.changes.each do |k, v|
|
|
64
|
+
embedded_doc_changes["#{rel}.#{k}"] = [v.first, v.last]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
embedded_doc_changes
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @param [String] relation
|
|
71
|
+
# @param [String] value
|
|
72
|
+
#
|
|
73
|
+
# @return [Hash<String, Array<(?,?)>>]
|
|
74
|
+
def embeds_one_changes_from_parent(relation, value)
|
|
22
75
|
relation = trackable_class.database_field_name(relation)
|
|
23
76
|
relation_class = trackable_class.relation_class_of(relation)
|
|
24
77
|
paranoia_field = Mongoid::History.trackable_class_settings(relation_class)[:paranoia_field]
|
|
25
78
|
original_value = value[0][paranoia_field].present? ? {} : format_embeds_one_relation(relation, value[0])
|
|
26
79
|
modified_value = value[1][paranoia_field].present? ? {} : format_embeds_one_relation(relation, value[1])
|
|
27
80
|
return if original_value == modified_value
|
|
28
|
-
|
|
81
|
+
|
|
82
|
+
{ relation => [original_value, modified_value] }
|
|
29
83
|
end
|
|
30
84
|
|
|
31
|
-
|
|
85
|
+
# @param [String] relation
|
|
86
|
+
# @param [String] value
|
|
87
|
+
#
|
|
88
|
+
# @return [Hash<Array<(?,?)>>]
|
|
89
|
+
def embeds_many_changes_from_parent(relation, value)
|
|
32
90
|
relation = trackable_class.database_field_name(relation)
|
|
33
91
|
relation_class = trackable_class.relation_class_of(relation)
|
|
34
92
|
paranoia_field = Mongoid::History.trackable_class_settings(relation_class)[:paranoia_field]
|
|
@@ -37,7 +95,8 @@ module Mongoid
|
|
|
37
95
|
modified_value = value[1].reject { |rel| rel[paranoia_field].present? }
|
|
38
96
|
.map { |v_attrs| format_embeds_many_relation(relation, v_attrs) }
|
|
39
97
|
return if original_value == modified_value
|
|
40
|
-
|
|
98
|
+
|
|
99
|
+
{ relation => [original_value, modified_value] }
|
|
41
100
|
end
|
|
42
101
|
end
|
|
43
102
|
end
|
|
@@ -95,12 +95,20 @@ module Mongoid
|
|
|
95
95
|
@options[:relations] = { embeds_one: {}, embeds_many: {} }
|
|
96
96
|
|
|
97
97
|
options[:on].each do |option|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
if option.is_a?(Hash)
|
|
99
|
+
option.each { |k, v| split_and_categorize(k => v) }
|
|
100
|
+
else
|
|
101
|
+
split_and_categorize(option)
|
|
102
|
+
end
|
|
101
103
|
end
|
|
102
104
|
end
|
|
103
105
|
|
|
106
|
+
def split_and_categorize(field_and_options)
|
|
107
|
+
field = get_database_field_name(field_and_options)
|
|
108
|
+
field_options = get_field_options(field_and_options)
|
|
109
|
+
categorize_tracked_option(field, field_options)
|
|
110
|
+
end
|
|
111
|
+
|
|
104
112
|
# Returns the database_field_name key for tracked option
|
|
105
113
|
#
|
|
106
114
|
# @param [ String | Symbol | Array | Hash ] option The field or relation name to track
|
|
@@ -29,8 +29,11 @@ module Mongoid
|
|
|
29
29
|
around_create :track_create, callback_options if history_options.options[:track_create]
|
|
30
30
|
around_destroy :track_destroy, callback_options if history_options.options[:track_destroy]
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
unless respond_to? :mongoid_history_options
|
|
33
|
+
class_attribute :mongoid_history_options, instance_accessor: false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
self.mongoid_history_options = history_options
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
def history_settings(options = {})
|
|
@@ -260,18 +263,43 @@ module Mongoid
|
|
|
260
263
|
@history_tracks = nil
|
|
261
264
|
end
|
|
262
265
|
|
|
266
|
+
# Transform hash of pair of changes into an `original` and `modified` hash
|
|
267
|
+
# Nested document keys (key name with dots) are expanded
|
|
268
|
+
#
|
|
269
|
+
# @param [Hash<Array>] changes
|
|
270
|
+
#
|
|
271
|
+
# @return [Array<Hash<?>,Hash<?>>] <description>
|
|
263
272
|
def transform_changes(changes)
|
|
264
273
|
original = {}
|
|
265
274
|
modified = {}
|
|
266
|
-
changes.each_pair do |k,
|
|
267
|
-
o, m =
|
|
268
|
-
original
|
|
269
|
-
modified
|
|
275
|
+
changes.each_pair do |k, modification_pair|
|
|
276
|
+
o, m = modification_pair
|
|
277
|
+
original.deep_merge!(expand_nested_document_key_value(k, o)) unless o.nil?
|
|
278
|
+
modified.deep_merge!(expand_nested_document_key_value(k, m)) unless m.nil?
|
|
270
279
|
end
|
|
271
280
|
|
|
272
281
|
[original, modified]
|
|
273
282
|
end
|
|
274
283
|
|
|
284
|
+
# Handle nested document tracking of changes
|
|
285
|
+
#
|
|
286
|
+
# @example
|
|
287
|
+
#
|
|
288
|
+
# expand_nested_document_key('embedded.document.changed_field', 'old'])
|
|
289
|
+
# #=> { 'embedded' => {'document' => { 'changed_field' => 'old' }}}
|
|
290
|
+
#
|
|
291
|
+
# @param [String] document_key key with dots
|
|
292
|
+
# @param [?] value
|
|
293
|
+
#
|
|
294
|
+
# @return [Hash<String, ?>]
|
|
295
|
+
def expand_nested_document_key_value(document_key, value)
|
|
296
|
+
expanded_key = value
|
|
297
|
+
document_key.to_s.split('.').reverse.each do |key|
|
|
298
|
+
expanded_key = { key => expanded_key }
|
|
299
|
+
end
|
|
300
|
+
expanded_key
|
|
301
|
+
end
|
|
302
|
+
|
|
275
303
|
def increment_current_version
|
|
276
304
|
current_version = (send(history_trackable_options[:version_field]) || 0) + 1
|
|
277
305
|
send("#{history_trackable_options[:version_field]}=", current_version)
|
|
@@ -287,7 +315,10 @@ module Mongoid
|
|
|
287
315
|
def track_history_for_action(action)
|
|
288
316
|
if track_history_for_action?(action)
|
|
289
317
|
current_version = increment_current_version
|
|
290
|
-
last_track = self.class.tracker_class.create!(
|
|
318
|
+
last_track = self.class.tracker_class.create!(
|
|
319
|
+
history_tracker_attributes(action.to_sym)
|
|
320
|
+
.merge(version: current_version, action: action.to_s, trackable: self)
|
|
321
|
+
)
|
|
291
322
|
end
|
|
292
323
|
|
|
293
324
|
clear_trackable_memoization
|
|
@@ -518,7 +549,7 @@ module Mongoid
|
|
|
518
549
|
end
|
|
519
550
|
|
|
520
551
|
def history_trackable_options
|
|
521
|
-
@history_trackable_options ||=
|
|
552
|
+
@history_trackable_options ||= mongoid_history_options.prepared
|
|
522
553
|
end
|
|
523
554
|
|
|
524
555
|
def clear_trackable_memoization
|
|
@@ -950,5 +950,27 @@ describe Mongoid::History do
|
|
|
950
950
|
expect(sausage.reload.flavour).to eq('Guinness')
|
|
951
951
|
end
|
|
952
952
|
end
|
|
953
|
+
|
|
954
|
+
describe 'changing collection' do
|
|
955
|
+
before :each do
|
|
956
|
+
class Fish
|
|
957
|
+
include Mongoid::Document
|
|
958
|
+
include Mongoid::History::Trackable
|
|
959
|
+
|
|
960
|
+
track_history on: [:species], modifier_field_optional: true
|
|
961
|
+
store_in collection: :animals
|
|
962
|
+
|
|
963
|
+
field :species
|
|
964
|
+
end
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
after :each do
|
|
968
|
+
Object.send(:remove_const, :Fish)
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
it 'should track history' do
|
|
972
|
+
Fish.new.save!
|
|
973
|
+
end
|
|
974
|
+
end
|
|
953
975
|
end
|
|
954
976
|
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Mongoid::History::Tracker do
|
|
4
|
+
describe 'Tracking of changes from embedded documents' do
|
|
5
|
+
before :each do
|
|
6
|
+
# Child model (will be embedded in Parent)
|
|
7
|
+
class Child
|
|
8
|
+
include Mongoid::Document
|
|
9
|
+
include Mongoid::History::Trackable
|
|
10
|
+
|
|
11
|
+
field :name
|
|
12
|
+
embedded_in :parent, inverse_of: :child
|
|
13
|
+
embeds_one :child, inverse_of: :parent, class_name: 'NestedChild'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# NestedChild model (will be embedded in Child)
|
|
17
|
+
class NestedChild
|
|
18
|
+
include Mongoid::Document
|
|
19
|
+
include Mongoid::History::Trackable
|
|
20
|
+
|
|
21
|
+
field :name
|
|
22
|
+
embedded_in :parent, inverse_of: :child, class_name: 'Child'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Parent model (embeds one Child)
|
|
26
|
+
class Parent
|
|
27
|
+
include Mongoid::Document
|
|
28
|
+
include Mongoid::History::Trackable
|
|
29
|
+
|
|
30
|
+
field :name, type: String
|
|
31
|
+
embeds_one :child
|
|
32
|
+
|
|
33
|
+
store_in collection: :parent
|
|
34
|
+
|
|
35
|
+
track_history(
|
|
36
|
+
on: %i[fields embedded_relations],
|
|
37
|
+
version_field: :version,
|
|
38
|
+
track_create: true,
|
|
39
|
+
track_update: true,
|
|
40
|
+
track_destroy: false,
|
|
41
|
+
modifier_field: nil
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
after :each do
|
|
47
|
+
Object.send(:remove_const, :Parent)
|
|
48
|
+
Object.send(:remove_const, :Child)
|
|
49
|
+
Object.send(:remove_const, :NestedChild)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context 'with a parent-child hierarchy' do
|
|
53
|
+
let(:parent) do
|
|
54
|
+
Parent.create!(name: 'bowser', child: Child.new(name: 'todd'))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'tracks history for the nested embedded documents in the parent' do
|
|
58
|
+
expect(parent.history_tracks.length).to eq(1)
|
|
59
|
+
|
|
60
|
+
aggregate_failures do
|
|
61
|
+
track = parent.history_tracks.last
|
|
62
|
+
expect(track.modified['name']).to eq('bowser')
|
|
63
|
+
expect(track.modified.dig('child', 'name')).to eq('todd')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
parent.update_attributes(name: 'brow')
|
|
67
|
+
expect(parent.history_tracks.length).to eq(2)
|
|
68
|
+
|
|
69
|
+
parent.child.name = 'mario'
|
|
70
|
+
parent.save!
|
|
71
|
+
expect(parent.history_tracks.length).to eq(3)
|
|
72
|
+
|
|
73
|
+
aggregate_failures do
|
|
74
|
+
track = parent.history_tracks.last
|
|
75
|
+
expect(track.original.dig('child', 'name')).to eq('todd')
|
|
76
|
+
expect(track.modified.dig('child', 'name')).to eq('mario')
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context 'with a deeply nested hierarchy' do
|
|
82
|
+
let(:parent) do
|
|
83
|
+
Parent.create!(
|
|
84
|
+
name: 'bowser',
|
|
85
|
+
child: Child.new(
|
|
86
|
+
name: 'todd',
|
|
87
|
+
child: NestedChild.new(name: 'peach')
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it 'tracks history for deeply nested embedded documents in parent' do
|
|
93
|
+
pending('Figure out a way to track deeply nested relation changes')
|
|
94
|
+
|
|
95
|
+
expect(parent.history_tracks.length).to eq(1)
|
|
96
|
+
|
|
97
|
+
aggregate_failures do
|
|
98
|
+
track = parent.history_tracks.last
|
|
99
|
+
expect(track.modified['name']).to eq('bowser')
|
|
100
|
+
expect(track.modified.dig('child', 'name')).to eq('todd')
|
|
101
|
+
expect(track.modified.dig('child', 'child', 'name')).to eq('peach')
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
parent.name = 'brow'
|
|
105
|
+
parent.child.name = 'mario'
|
|
106
|
+
parent.child.child.name = 'luigi'
|
|
107
|
+
parent.save!
|
|
108
|
+
expect(parent.history_tracks.length).to eq(2)
|
|
109
|
+
|
|
110
|
+
aggregate_failures do
|
|
111
|
+
track = parent.history_tracks.last
|
|
112
|
+
expect(track.original['name']).to eq('bowser')
|
|
113
|
+
expect(track.modified['name']).to eq('brow')
|
|
114
|
+
|
|
115
|
+
expect(track.original['child']['name']).to eq('todd')
|
|
116
|
+
expect(track.modified['child']['name']).to eq('mario')
|
|
117
|
+
|
|
118
|
+
expect(track.original['child']['child']['name']).to eq('peach')
|
|
119
|
+
expect(track.modified['child']['child']['name']).to eq('luigi')
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
data/spec/unit/history_spec.rb
CHANGED
|
@@ -34,4 +34,25 @@ describe Mongoid::History do
|
|
|
34
34
|
it { expect(described_class.trackable_class_settings(ModelOne)).to eq(paranoia_field: 'deleted_at') }
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
|
+
|
|
38
|
+
describe '#reset!' do
|
|
39
|
+
before :each do
|
|
40
|
+
class ModelTwo
|
|
41
|
+
include Mongoid::Document
|
|
42
|
+
include Mongoid::History::Trackable
|
|
43
|
+
|
|
44
|
+
track_history
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
after :each do
|
|
49
|
+
Object.send(:remove_const, :ModelTwo)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'should remove all configurations' do
|
|
53
|
+
expect(ModelTwo).to have_attributes mongoid_history_options: be_a(Mongoid::History::Options)
|
|
54
|
+
Mongoid::History.reset!
|
|
55
|
+
expect(ModelTwo).to_not respond_to :mongoid_history_options
|
|
56
|
+
end
|
|
57
|
+
end
|
|
37
58
|
end
|
data/spec/unit/options_spec.rb
CHANGED
|
@@ -275,6 +275,15 @@ describe Mongoid::History::Options do
|
|
|
275
275
|
it { expect(subject[:relations][:embeds_many]).to eq('emb_threes' => %w[_id fmb]) }
|
|
276
276
|
end
|
|
277
277
|
|
|
278
|
+
context 'with fields, and multiple embeds_one, and embeds_many relations' do
|
|
279
|
+
let(:options) { { on: [:foo, :bar, :emb_two, { emb_threes: %i[f_em_foo f_em_bar], emb_fours: :f_em_baz }] } }
|
|
280
|
+
it 'should categorize fields and associations correctly' do
|
|
281
|
+
expect(subject[:fields]).to eq(%w[foo b])
|
|
282
|
+
expect(subject[:relations][:embeds_one]).to eq('emtw' => %w[_id f_em_baz])
|
|
283
|
+
expect(subject[:relations][:embeds_many]).to eq('emb_threes' => %w[_id f_em_foo fmb], 'emfs' => %w[_id f_em_baz])
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
278
287
|
context 'with field alias' do
|
|
279
288
|
let(:options) { { on: :bar } }
|
|
280
289
|
it { expect(subject[:fields]).to eq %w[b] }
|
data/spec/unit/trackable_spec.rb
CHANGED
|
@@ -37,12 +37,6 @@ describe Mongoid::History::Trackable do
|
|
|
37
37
|
expect(MyModel).to respond_to :track_history
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
it 'should append trackable_class_options ONLY when #track_history is called' do
|
|
41
|
-
expect(Mongoid::History.trackable_class_options).to be_blank
|
|
42
|
-
MyModel.track_history
|
|
43
|
-
expect(Mongoid::History.trackable_class_options.keys).to eq([:my_model])
|
|
44
|
-
end
|
|
45
|
-
|
|
46
40
|
describe '#track_history' do
|
|
47
41
|
before :each do
|
|
48
42
|
class MyModelWithNoModifier
|
|
@@ -85,7 +79,7 @@ describe Mongoid::History::Trackable do
|
|
|
85
79
|
let(:reserved_fields) { %w[_id version modifier_id] }
|
|
86
80
|
|
|
87
81
|
it 'should have default options' do
|
|
88
|
-
expect(
|
|
82
|
+
expect(MyModel.mongoid_history_options.prepared).to eq(expected_option)
|
|
89
83
|
end
|
|
90
84
|
|
|
91
85
|
it 'should define callback function #track_update' do
|
|
@@ -266,7 +260,7 @@ describe Mongoid::History::Trackable do
|
|
|
266
260
|
end
|
|
267
261
|
|
|
268
262
|
it 'should have default options' do
|
|
269
|
-
expect(
|
|
263
|
+
expect(MyModel.mongoid_history_options.prepared).to eq(expected_option)
|
|
270
264
|
end
|
|
271
265
|
|
|
272
266
|
it 'should define #history_trackable_options' do
|
|
@@ -784,4 +778,62 @@ describe Mongoid::History::Trackable do
|
|
|
784
778
|
end.to change(Tracker, :count).by(0)
|
|
785
779
|
end
|
|
786
780
|
end
|
|
781
|
+
|
|
782
|
+
context 'changing collection' do
|
|
783
|
+
before :each do
|
|
784
|
+
class Fish
|
|
785
|
+
include Mongoid::Document
|
|
786
|
+
include Mongoid::History::Trackable
|
|
787
|
+
|
|
788
|
+
track_history on: [:species], modifier_field_optional: true
|
|
789
|
+
store_in collection: :animals
|
|
790
|
+
|
|
791
|
+
field :species
|
|
792
|
+
end
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
after :each do
|
|
796
|
+
Object.send(:remove_const, :Fish)
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
it 'should track history' do
|
|
800
|
+
expect do
|
|
801
|
+
expect { Fish.new.save! }.to_not raise_error
|
|
802
|
+
end.to change(Tracker, :count).by(1)
|
|
803
|
+
end
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
context "extending a #{described_class}" do
|
|
807
|
+
before :each do
|
|
808
|
+
MyModel.track_history
|
|
809
|
+
|
|
810
|
+
class CustomTracker < MyModel
|
|
811
|
+
field :key
|
|
812
|
+
|
|
813
|
+
track_history on: :key, changes_method: :my_changes, track_create: true
|
|
814
|
+
|
|
815
|
+
def my_changes
|
|
816
|
+
changes.merge('key' => "Save history-#{key}")
|
|
817
|
+
end
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
MyModel.history_trackable_options
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
after :each do
|
|
824
|
+
Object.send(:remove_const, :CustomTracker)
|
|
825
|
+
end
|
|
826
|
+
|
|
827
|
+
it 'should not override in parent class' do
|
|
828
|
+
expect(MyModel.history_trackable_options[:changes_method]).to eq :changes
|
|
829
|
+
expect(CustomTracker.history_trackable_options[:changes_method]).to eq :my_changes
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
it 'should default to :changes' do
|
|
833
|
+
m = MyModel.create!(modifier: user)
|
|
834
|
+
expect(m).to receive(:changes).exactly(3).times.and_call_original
|
|
835
|
+
expect(m).not_to receive(:my_changes)
|
|
836
|
+
m.save!
|
|
837
|
+
end
|
|
838
|
+
end
|
|
787
839
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mongoid-history
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aaron Qian
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date:
|
|
13
|
+
date: 2019-12-02 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: easy_diff
|
|
@@ -117,6 +117,7 @@ files:
|
|
|
117
117
|
- spec/integration/multi_relation_spec.rb
|
|
118
118
|
- spec/integration/multiple_trackers_spec.rb
|
|
119
119
|
- spec/integration/nested_embedded_documents_spec.rb
|
|
120
|
+
- spec/integration/nested_embedded_documents_tracked_in_parent_spec.rb
|
|
120
121
|
- spec/integration/nested_embedded_polymorphic_documents_spec.rb
|
|
121
122
|
- spec/integration/subclasses_spec.rb
|
|
122
123
|
- spec/integration/track_history_order_spec.rb
|
|
@@ -157,8 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
157
158
|
- !ruby/object:Gem::Version
|
|
158
159
|
version: '0'
|
|
159
160
|
requirements: []
|
|
160
|
-
|
|
161
|
-
rubygems_version: 2.6.13
|
|
161
|
+
rubygems_version: 3.0.3
|
|
162
162
|
signing_key:
|
|
163
163
|
specification_version: 4
|
|
164
164
|
summary: Track and audit, undo and redo changes on Mongoid documents.
|
|
@@ -168,6 +168,7 @@ test_files:
|
|
|
168
168
|
- spec/integration/multi_relation_spec.rb
|
|
169
169
|
- spec/integration/multiple_trackers_spec.rb
|
|
170
170
|
- spec/integration/nested_embedded_documents_spec.rb
|
|
171
|
+
- spec/integration/nested_embedded_documents_tracked_in_parent_spec.rb
|
|
171
172
|
- spec/integration/nested_embedded_polymorphic_documents_spec.rb
|
|
172
173
|
- spec/integration/subclasses_spec.rb
|
|
173
174
|
- spec/integration/track_history_order_spec.rb
|