mongoid-history 0.8.3 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
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