mongoid-history 0.8.3 → 0.8.5

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -1
  3. data/.document +5 -5
  4. data/.github/workflows/test.yml +72 -0
  5. data/.gitignore +46 -46
  6. data/.rspec +2 -2
  7. data/.rubocop.yml +6 -6
  8. data/.rubocop_todo.yml +99 -99
  9. data/CHANGELOG.md +173 -163
  10. data/CONTRIBUTING.md +117 -118
  11. data/Dangerfile +1 -1
  12. data/Gemfile +49 -40
  13. data/LICENSE.txt +20 -20
  14. data/README.md +609 -608
  15. data/RELEASING.md +66 -67
  16. data/Rakefile +24 -24
  17. data/UPGRADING.md +53 -53
  18. data/lib/mongoid/history/attributes/base.rb +72 -72
  19. data/lib/mongoid/history/attributes/create.rb +45 -45
  20. data/lib/mongoid/history/attributes/destroy.rb +34 -34
  21. data/lib/mongoid/history/attributes/update.rb +104 -104
  22. data/lib/mongoid/history/options.rb +177 -177
  23. data/lib/mongoid/history/trackable.rb +588 -583
  24. data/lib/mongoid/history/tracker.rb +247 -247
  25. data/lib/mongoid/history/version.rb +5 -5
  26. data/lib/mongoid/history.rb +77 -77
  27. data/lib/mongoid-history.rb +1 -1
  28. data/mongoid-history.gemspec +25 -25
  29. data/perf/benchmark_modified_attributes_for_create.rb +65 -65
  30. data/perf/gc_suite.rb +21 -21
  31. data/spec/integration/embedded_in_polymorphic_spec.rb +112 -112
  32. data/spec/integration/integration_spec.rb +976 -976
  33. data/spec/integration/multi_relation_spec.rb +47 -47
  34. data/spec/integration/multiple_trackers_spec.rb +68 -68
  35. data/spec/integration/nested_embedded_documents_spec.rb +64 -64
  36. data/spec/integration/nested_embedded_documents_tracked_in_parent_spec.rb +124 -124
  37. data/spec/integration/nested_embedded_polymorphic_documents_spec.rb +115 -115
  38. data/spec/integration/subclasses_spec.rb +47 -47
  39. data/spec/integration/track_history_order_spec.rb +84 -84
  40. data/spec/integration/validation_failure_spec.rb +76 -76
  41. data/spec/spec_helper.rb +32 -30
  42. data/spec/support/error_helpers.rb +7 -0
  43. data/spec/support/mongoid.rb +11 -11
  44. data/spec/support/mongoid_history.rb +12 -12
  45. data/spec/unit/attributes/base_spec.rb +141 -141
  46. data/spec/unit/attributes/create_spec.rb +342 -342
  47. data/spec/unit/attributes/destroy_spec.rb +228 -228
  48. data/spec/unit/attributes/update_spec.rb +342 -342
  49. data/spec/unit/callback_options_spec.rb +165 -165
  50. data/spec/unit/embedded_methods_spec.rb +87 -87
  51. data/spec/unit/history_spec.rb +58 -58
  52. data/spec/unit/my_instance_methods_spec.rb +555 -555
  53. data/spec/unit/options_spec.rb +365 -365
  54. data/spec/unit/singleton_methods_spec.rb +406 -406
  55. data/spec/unit/store/default_store_spec.rb +11 -11
  56. data/spec/unit/store/request_store_spec.rb +13 -13
  57. data/spec/unit/trackable_spec.rb +1057 -987
  58. data/spec/unit/tracker_spec.rb +190 -190
  59. metadata +9 -7
  60. data/.travis.yml +0 -36
@@ -1,47 +1,47 @@
1
- require 'spec_helper'
2
-
3
- describe Mongoid::History::Tracker do
4
- before :each do
5
- class Model
6
- include Mongoid::Document
7
- include Mongoid::History::Trackable
8
-
9
- field :name, type: String
10
- belongs_to :user, inverse_of: :models
11
- has_and_belongs_to_many :external_users, class_name: 'User', inverse_of: :external_models
12
-
13
- track_history on: %i[name user external_user_ids], modifier_field_inverse_of: nil
14
- end
15
-
16
- class User
17
- include Mongoid::Document
18
-
19
- has_many :models, dependent: :destroy, inverse_of: :user
20
- has_and_belongs_to_many :external_model, class_name: 'Model', inverse_of: :external_users
21
- end
22
- end
23
-
24
- after :each do
25
- Object.send(:remove_const, :Model)
26
- Object.send(:remove_const, :User)
27
- end
28
-
29
- let(:user) { User.create! }
30
- let(:model) { Model.create!(name: 'Foo', user: user, modifier: user) }
31
-
32
- it 'should be possible to undo when having multiple relations to modifier class' do
33
- model.update_attributes!(name: 'Bar', modifier: user)
34
-
35
- model.undo! user
36
- expect(model.name).to eq 'Foo'
37
-
38
- model.redo! user, 2
39
- expect(model.name).to eq 'Bar'
40
- end
41
-
42
- it 'should track foreign key relations' do
43
- expect(Model.tracked_field?(:external_user_ids)).to be true
44
- expect(Model.tracked_field?(:user)).to be true
45
- expect(Model.tracked_field?(:user_id)).to be true
46
- end
47
- end
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::History::Tracker do
4
+ before :each do
5
+ class Model
6
+ include Mongoid::Document
7
+ include Mongoid::History::Trackable
8
+
9
+ field :name, type: String
10
+ belongs_to :user, inverse_of: :models
11
+ has_and_belongs_to_many :external_users, class_name: 'User', inverse_of: :external_models
12
+
13
+ track_history on: %i[name user external_user_ids], modifier_field_inverse_of: nil
14
+ end
15
+
16
+ class User
17
+ include Mongoid::Document
18
+
19
+ has_many :models, dependent: :destroy, inverse_of: :user
20
+ has_and_belongs_to_many :external_model, class_name: 'Model', inverse_of: :external_users
21
+ end
22
+ end
23
+
24
+ after :each do
25
+ Object.send(:remove_const, :Model)
26
+ Object.send(:remove_const, :User)
27
+ end
28
+
29
+ let(:user) { User.create! }
30
+ let(:model) { Model.create!(name: 'Foo', user: user, modifier: user) }
31
+
32
+ it 'should be possible to undo when having multiple relations to modifier class' do
33
+ model.update_attributes!(name: 'Bar', modifier: user)
34
+
35
+ model.undo! user
36
+ expect(model.name).to eq 'Foo'
37
+
38
+ model.redo! user, 2
39
+ expect(model.name).to eq 'Bar'
40
+ end
41
+
42
+ it 'should track foreign key relations' do
43
+ expect(Model.tracked_field?(:external_user_ids)).to be true
44
+ expect(Model.tracked_field?(:user)).to be true
45
+ expect(Model.tracked_field?(:user_id)).to be true
46
+ end
47
+ end
@@ -1,68 +1,68 @@
1
- require 'spec_helper'
2
-
3
- describe Mongoid::History do
4
- before :each do
5
- class First
6
- include Mongoid::Document
7
- include Mongoid::History::Trackable
8
-
9
- field :text, type: String
10
- track_history on: [:text], tracker_class_name: :first_history_tracker
11
- end
12
-
13
- class Second
14
- include Mongoid::Document
15
- include Mongoid::History::Trackable
16
-
17
- field :text, type: String
18
- track_history on: [:text], tracker_class_name: :second_history_tracker
19
- end
20
-
21
- class User
22
- include Mongoid::Document
23
- end
24
-
25
- class FirstHistoryTracker
26
- include Mongoid::History::Tracker
27
- end
28
-
29
- class SecondHistoryTracker
30
- include Mongoid::History::Tracker
31
- end
32
- end
33
-
34
- after :each do
35
- Object.send(:remove_const, :First)
36
- Object.send(:remove_const, :Second)
37
- Object.send(:remove_const, :User)
38
- Object.send(:remove_const, :FirstHistoryTracker)
39
- Object.send(:remove_const, :SecondHistoryTracker)
40
- end
41
-
42
- let(:user) { User.create! }
43
-
44
- it 'should be possible to have different trackers for each class' do
45
- expect(FirstHistoryTracker.count).to eq(0)
46
- expect(SecondHistoryTracker.count).to eq(0)
47
- expect(First.tracker_class).to be FirstHistoryTracker
48
- expect(Second.tracker_class).to be SecondHistoryTracker
49
-
50
- foo = First.create!(modifier: user)
51
- bar = Second.create!(modifier: user)
52
-
53
- expect(FirstHistoryTracker.count).to eq 1
54
- expect(SecondHistoryTracker.count).to eq 1
55
-
56
- foo.update_attributes!(text: "I'm foo")
57
- bar.update_attributes!(text: "I'm bar")
58
-
59
- expect(FirstHistoryTracker.count).to eq 2
60
- expect(SecondHistoryTracker.count).to eq 2
61
-
62
- foo.destroy
63
- bar.destroy
64
-
65
- expect(FirstHistoryTracker.count).to eq 3
66
- expect(SecondHistoryTracker.count).to eq 3
67
- end
68
- end
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::History do
4
+ before :each do
5
+ class First
6
+ include Mongoid::Document
7
+ include Mongoid::History::Trackable
8
+
9
+ field :text, type: String
10
+ track_history on: [:text], tracker_class_name: :first_history_tracker
11
+ end
12
+
13
+ class Second
14
+ include Mongoid::Document
15
+ include Mongoid::History::Trackable
16
+
17
+ field :text, type: String
18
+ track_history on: [:text], tracker_class_name: :second_history_tracker
19
+ end
20
+
21
+ class User
22
+ include Mongoid::Document
23
+ end
24
+
25
+ class FirstHistoryTracker
26
+ include Mongoid::History::Tracker
27
+ end
28
+
29
+ class SecondHistoryTracker
30
+ include Mongoid::History::Tracker
31
+ end
32
+ end
33
+
34
+ after :each do
35
+ Object.send(:remove_const, :First)
36
+ Object.send(:remove_const, :Second)
37
+ Object.send(:remove_const, :User)
38
+ Object.send(:remove_const, :FirstHistoryTracker)
39
+ Object.send(:remove_const, :SecondHistoryTracker)
40
+ end
41
+
42
+ let(:user) { User.create! }
43
+
44
+ it 'should be possible to have different trackers for each class' do
45
+ expect(FirstHistoryTracker.count).to eq(0)
46
+ expect(SecondHistoryTracker.count).to eq(0)
47
+ expect(First.tracker_class).to be FirstHistoryTracker
48
+ expect(Second.tracker_class).to be SecondHistoryTracker
49
+
50
+ foo = First.create!(modifier: user)
51
+ bar = Second.create!(modifier: user)
52
+
53
+ expect(FirstHistoryTracker.count).to eq 1
54
+ expect(SecondHistoryTracker.count).to eq 1
55
+
56
+ foo.update_attributes!(text: "I'm foo")
57
+ bar.update_attributes!(text: "I'm bar")
58
+
59
+ expect(FirstHistoryTracker.count).to eq 2
60
+ expect(SecondHistoryTracker.count).to eq 2
61
+
62
+ foo.destroy
63
+ bar.destroy
64
+
65
+ expect(FirstHistoryTracker.count).to eq 3
66
+ expect(SecondHistoryTracker.count).to eq 3
67
+ end
68
+ end
@@ -1,64 +1,64 @@
1
- require 'spec_helper'
2
-
3
- describe Mongoid::History::Tracker do
4
- before :each do
5
- class ModelOne
6
- include Mongoid::Document
7
- include Mongoid::History::Trackable
8
-
9
- field :name, type: String
10
- belongs_to :user, inverse_of: :model_ones
11
- embeds_many :emb_ones
12
-
13
- track_history
14
- end
15
-
16
- class EmbOne
17
- include Mongoid::Document
18
- include Mongoid::History::Trackable
19
-
20
- field :name
21
- embeds_many :emb_twos, store_as: :ems
22
- embedded_in :model_one
23
-
24
- track_history
25
- end
26
-
27
- class EmbTwo
28
- include Mongoid::Document
29
- include Mongoid::History::Trackable
30
-
31
- field :name
32
- embedded_in :emb_one
33
-
34
- track_history scope: :model_one
35
- end
36
-
37
- class User
38
- include Mongoid::Document
39
-
40
- has_many :model_ones, dependent: :destroy, inverse_of: :user
41
- end
42
- end
43
-
44
- after :each do
45
- Object.send(:remove_const, :ModelOne)
46
- Object.send(:remove_const, :EmbOne)
47
- Object.send(:remove_const, :EmbTwo)
48
- Object.send(:remove_const, :User)
49
- end
50
-
51
- let(:user) { User.create! }
52
-
53
- it 'should be able to track history for nested embedded documents' do
54
- model = ModelOne.create!(name: 'm1name', user: user, modifier: user)
55
- embedded1 = model.emb_ones.create!(name: 'e1name', modifier: user)
56
- embedded2 = embedded1.emb_twos.create!(name: 'e2name', modifier: user)
57
-
58
- embedded2.update_attributes!(name: 'a new name')
59
-
60
- model.history_tracks[-1].undo! user
61
- expect(embedded1.reload.name).to eq('e1name')
62
- expect(embedded2.reload.name).to eq('e2name')
63
- end
64
- end
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::History::Tracker do
4
+ before :each do
5
+ class ModelOne
6
+ include Mongoid::Document
7
+ include Mongoid::History::Trackable
8
+
9
+ field :name, type: String
10
+ belongs_to :user, inverse_of: :model_ones
11
+ embeds_many :emb_ones
12
+
13
+ track_history
14
+ end
15
+
16
+ class EmbOne
17
+ include Mongoid::Document
18
+ include Mongoid::History::Trackable
19
+
20
+ field :name
21
+ embeds_many :emb_twos, store_as: :ems
22
+ embedded_in :model_one
23
+
24
+ track_history
25
+ end
26
+
27
+ class EmbTwo
28
+ include Mongoid::Document
29
+ include Mongoid::History::Trackable
30
+
31
+ field :name
32
+ embedded_in :emb_one
33
+
34
+ track_history scope: :model_one
35
+ end
36
+
37
+ class User
38
+ include Mongoid::Document
39
+
40
+ has_many :model_ones, dependent: :destroy, inverse_of: :user
41
+ end
42
+ end
43
+
44
+ after :each do
45
+ Object.send(:remove_const, :ModelOne)
46
+ Object.send(:remove_const, :EmbOne)
47
+ Object.send(:remove_const, :EmbTwo)
48
+ Object.send(:remove_const, :User)
49
+ end
50
+
51
+ let(:user) { User.create! }
52
+
53
+ it 'should be able to track history for nested embedded documents' do
54
+ model = ModelOne.create!(name: 'm1name', user: user, modifier: user)
55
+ embedded1 = model.emb_ones.create!(name: 'e1name', modifier: user)
56
+ embedded2 = embedded1.emb_twos.create!(name: 'e2name', modifier: user)
57
+
58
+ embedded2.update_attributes!(name: 'a new name')
59
+
60
+ model.history_tracks[-1].undo! user
61
+ expect(embedded1.reload.name).to eq('e1name')
62
+ expect(embedded2.reload.name).to eq('e2name')
63
+ end
64
+ end
@@ -1,124 +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
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