mongoid_relations_dirty_tracking 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9bd7befbb1f28738d4b2466c5fee8a4f73f82eb2
4
+ data.tar.gz: 5f86d528912d3a3a90e3306ac8b60069a90cea37
5
+ SHA512:
6
+ metadata.gz: f5f28400a832ca7b5627ce13b4aea1c2c7ba91a885c8b23ab71b76034ba8a59fb4df070f713b6d2430e5abf494c76cb6bd57dfb06f368423dc50bd106306bea2
7
+ data.tar.gz: 3d61e3f9e0a3461996150562c9321545d8cb9c3f9ea8bace95d28c709645126360cb4571ef8f244535b34d16adf7963f3fd2e8c8b1aecd8d3a2c82fd4fba4d42
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mongoid_track_embedded_changes.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 David Sevcik
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # Mongoid::RelationsDirtyTracking
2
+
3
+ Mongoid extension for tracking changes on document relations.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'mongoid_relations_dirty_tracking', github: 'versative/mongoid_relations_dirty_tracking'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ ## Usage
16
+
17
+ ```ruby
18
+ class SampleDocument
19
+ include Mongoid::Document
20
+ include Mongoid::RelationsDirtyTracking
21
+
22
+ embeds_one :foo
23
+ has_many :bars
24
+
25
+ field :title, type: String
26
+ end
27
+
28
+ doc = SampleDocument.create
29
+ doc.foo = Foo.new(title: 'foo')
30
+ doc.bars << Bar.new(title: 'bar')
31
+ doc.title = 'New title'
32
+
33
+ doc.relations_changed? # => true
34
+ doc.relation_changes # => {"foo" => [nil, {"_id"=>"524c35ad1ac1c23084000040", "title" => "foo"}], "bars" => [nil, [{"_id"=>"524c35ad1ac1c23084000083"}]]}
35
+ doc.changed? # => true
36
+ doc.changes # => {"title" => [nil, "New title"], "foo" => [nil, {"_id"=>"524c35ad1ac1c23084000040", "title" => "foo"}], "bars" => [nil, [{"_id"=>"524c35ad1ac1c23084000083"}]]}
37
+
38
+ doc.save
39
+ doc.relations_changed? # => false
40
+ doc.relation_changes # => {}
41
+ doc.changed? # => false
42
+ doc.changes # => {}
43
+ ```
44
+
45
+ ## Contributing
46
+
47
+ 1. Fork it
48
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,5 @@
1
+ module Mongoid
2
+ module RelationsDirtyTracking
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,54 @@
1
+ module Mongoid
2
+ module RelationsDirtyTracking
3
+ module Versioning
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ alias_method_chain :revise, :relations
8
+ alias_method_chain :versioned_changes, :relations
9
+ alias_method_chain :revisable?, :relations
10
+ end
11
+
12
+
13
+ def revise_with_relations
14
+ previous = previous_revision
15
+ if previous && (versioned_attributes_changed? || relations_changed?)
16
+ new_version = versions.build(previous.versioned_attributes, without_protection: true)
17
+
18
+ rel_changes = relation_changes
19
+
20
+ self.class.tracked_relations.each do |rel_name|
21
+ # from some reason previous contaion also newly added relations
22
+ prev_value = rel_changes.include?(rel_name) ? rel_changes[rel_name][0] : previous[rel_name.to_sym]
23
+ new_version.send "#{rel_name}=", preserve_versioned_relation(reflect_on_association(rel_name), prev_value)
24
+ end
25
+
26
+
27
+ if version_max.present? && versions.length > version_max
28
+ deleted = versions.first
29
+ if deleted.paranoid?
30
+ versions.delete_one(deleted)
31
+ collection.find(atomic_selector).
32
+ update({ "$pull" => { "versions" => { "version" => deleted.version }}})
33
+ else
34
+ versions.delete(deleted)
35
+ end
36
+ end
37
+ self.version = (version || 1) + 1
38
+ end
39
+ end
40
+
41
+ def revisable_with_relations?
42
+ (versioned_attributes_changed? || relations_changed?) && !versionless?
43
+ end
44
+
45
+ def versioned_changes_with_relations
46
+ only_versioned_attributes(changes_without_relations.except("updated_at"))
47
+ end
48
+
49
+ def preserve_versioned_relation(rel_meta, value)
50
+ value
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,108 @@
1
+ require 'mongoid'
2
+ require 'active_support/concern'
3
+ require 'active_support/core_ext/module/aliasing'
4
+
5
+
6
+ module Mongoid
7
+ module RelationsDirtyTracking
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ after_initialize :store_relations_shadow
12
+ after_save :store_relations_shadow
13
+
14
+ alias_method_chain :changes, :relations
15
+ alias_method_chain :changed?, :relations
16
+
17
+ cattr_accessor :relations_dirty_tracking_options
18
+ self.relations_dirty_tracking_options = { only: [], except: ['versions'] }
19
+
20
+ if self.include? Mongoid::Versioning
21
+ include Mongoid::RelationsDirtyTracking::Versioning
22
+ end
23
+ end
24
+
25
+
26
+ def store_relations_shadow
27
+ @relations_shadow = {}
28
+ self.class.tracked_relations.each do |rel_name|
29
+ @relations_shadow[rel_name] = tracked_relation_attributes(rel_name)
30
+ end
31
+ end
32
+
33
+
34
+ def relation_changes
35
+ changes = {}
36
+ @relations_shadow.each_pair do |rel_name, shadow_values|
37
+ current_values = tracked_relation_attributes(rel_name)
38
+ if current_values != shadow_values
39
+ changes[rel_name] = [shadow_values, current_values]
40
+ end
41
+ end
42
+ changes
43
+ end
44
+
45
+
46
+ def relations_changed?
47
+ !relation_changes.empty?
48
+ end
49
+
50
+
51
+ def changed_with_relations?
52
+ changed_without_relations? or relations_changed?
53
+ end
54
+
55
+
56
+ def changes_with_relations
57
+ (changes_without_relations || {}).merge relation_changes
58
+ end
59
+
60
+
61
+ def tracked_relation_attributes(rel_name)
62
+ rel_name = rel_name.to_s
63
+ values = nil
64
+ if meta = relations[rel_name]
65
+ values = if meta.relation == Mongoid::Relations::Embedded::One
66
+ send(rel_name) && send(rel_name).attributes.clone.delete_if {|key, _| key == 'updated_at' }
67
+ elsif meta.relation == Mongoid::Relations::Embedded::Many
68
+ send(rel_name) && send(rel_name).map {|child| child.attributes.clone.delete_if {|key, _| key == 'updated_at' } }
69
+ elsif meta.relation == Mongoid::Relations::Referenced::One
70
+ send(rel_name) && { "#{meta.key}" => send(rel_name)[meta.key] }
71
+ elsif meta.relation == Mongoid::Relations::Referenced::Many
72
+ send("#{rel_name.singularize}_ids").map {|id| { "#{meta.key}" => id } }
73
+ elsif meta.relation == Mongoid::Relations::Referenced::ManyToMany
74
+ send("#{rel_name.singularize}_ids").map {|id| { "#{meta.primary_key}" => id } }
75
+ elsif meta.relation == Mongoid::Relations::Referenced::In
76
+ send(meta.foreign_key) && { "#{meta.foreign_key}" => send(meta.foreign_key)}
77
+ end
78
+ end
79
+ values
80
+ end
81
+
82
+
83
+ module ClassMethods
84
+
85
+ def relations_dirty_tracking(options = {})
86
+ relations_dirty_tracking_options[:only] += [options[:only] || []].flatten.map(&:to_s)
87
+ relations_dirty_tracking_options[:except] += [options[:except] || []].flatten.map(&:to_s)
88
+ end
89
+
90
+
91
+ def track_relation?(rel_name)
92
+ rel_name = rel_name.to_s
93
+ options = relations_dirty_tracking_options
94
+ to_track = (!options[:only].blank? && options[:only].include?(rel_name)) \
95
+ || (options[:only].blank? && !options[:except].include?(rel_name))
96
+
97
+ to_track && [Mongoid::Relations::Embedded::One, Mongoid::Relations::Embedded::Many,
98
+ Mongoid::Relations::Referenced::One, Mongoid::Relations::Referenced::Many,
99
+ Mongoid::Relations::Referenced::ManyToMany, Mongoid::Relations::Referenced::In].include?(relations[rel_name].try(:relation))
100
+ end
101
+
102
+
103
+ def tracked_relations
104
+ @tracked_relations ||= relations.keys.select {|rel_name| track_relation?(rel_name) }
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,2 @@
1
+ require "mongoid/relations_dirty_tracking"
2
+ require 'mongoid/relations_dirty_tracking/versioning'
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ require File.expand_path('../lib/mongoid/relations_dirty_tracking/version', __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "mongoid_relations_dirty_tracking"
6
+ spec.version = Mongoid::RelationsDirtyTracking::VERSION
7
+ spec.authors = ["David Sevcik"]
8
+ spec.email = ["david.sevcik@gmail.com"]
9
+ spec.description = "Mongoid extension for tracking changes on document relations"
10
+ spec.summary = "Mongoid extension for tracking changes on document relations"
11
+ spec.homepage = "http://github.com/versative/relations_dirty_tracking"
12
+ spec.license = "MIT"
13
+
14
+ spec.add_runtime_dependency 'activesupport', '~> 3.0'
15
+ spec.add_runtime_dependency 'mongoid', '>= 3.1.0', '< 4.0'
16
+
17
+ spec.add_development_dependency "bundler", "~> 1.3"
18
+ spec.add_development_dependency "rake"
19
+ spec.add_development_dependency "rspec", "~> 2.8"
20
+ spec.add_development_dependency "pry"
21
+
22
+ spec.files = `git ls-files`.split($/)
23
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
25
+ spec.require_paths = ["lib"]
26
+ end
@@ -0,0 +1,382 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe Mongoid::RelationsDirtyTracking do
5
+ subject { TestDocument.create }
6
+
7
+ its(:changed?) { should be_false }
8
+ its(:children_changed?) { should be_false }
9
+ its(:relations_changed?) { should be_false }
10
+ its(:changed_with_relations?) { should be_false }
11
+
12
+
13
+ context "embeds_one relationship" do
14
+ context "when adding document" do
15
+ before :each do
16
+ @embedded_doc = TestEmbeddedDocument.new
17
+ subject.one_document = @embedded_doc
18
+ end
19
+
20
+ its(:changed?) { should be_true }
21
+ its(:children_changed?) { should be_false }
22
+ its(:relations_changed?) { should be_true }
23
+ its(:changed_with_relations?) { should be_true }
24
+ its(:changes_with_relations) { should include(subject.relation_changes) }
25
+
26
+ describe "#relation_changes" do
27
+ it "returns array with differences" do
28
+ expect(subject.relation_changes['one_document']).to eq([nil, @embedded_doc.attributes])
29
+ end
30
+ end
31
+ end
32
+
33
+
34
+ context "when removing document" do
35
+ before :each do
36
+ @embedded_doc = TestEmbeddedDocument.new
37
+ subject.one_document = @embedded_doc
38
+ subject.save!
39
+ subject.one_document = nil
40
+ end
41
+
42
+ its(:changed?) { should be_true }
43
+ its(:children_changed?) { should be_false }
44
+ its(:relations_changed?) { should be_true }
45
+ its(:changed_with_relations?) { should be_true }
46
+ its(:changes_with_relations) { should include(subject.relation_changes) }
47
+
48
+ describe "#relation_changes" do
49
+ it "returns array with differences" do
50
+ expect(subject.relation_changes['one_document']).to eq([@embedded_doc.attributes, nil])
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+ context "when changing value on embedded document" do
57
+ before :each do
58
+ @embedded_doc = TestEmbeddedDocument.new
59
+ subject.one_document = @embedded_doc
60
+ subject.save!
61
+ subject.one_document.title = 'foobar'
62
+ end
63
+
64
+ its(:changed?) { should be_true }
65
+ its(:children_changed?) { should be_true }
66
+ its(:relations_changed?) { should be_true }
67
+ its(:changed_with_relations?) { should be_true }
68
+ its(:changes_with_relations) { should include(subject.relation_changes) }
69
+
70
+ describe "#relation_changes" do
71
+ it "returns array with differences" do
72
+ old_attributes = @embedded_doc.attributes.clone.delete_if {|key, val| key == "title" }
73
+ expect(subject.relation_changes['one_document']).to eq([old_attributes, @embedded_doc.attributes])
74
+ end
75
+ end
76
+ end
77
+
78
+ context "when just updated_at is changed on embedded document" do
79
+ before :each do
80
+ embedded_doc = Class.new(TestEmbeddedDocument) { include Mongoid::Timestamps }.new
81
+ subject.one_document = @embedded_doc
82
+ subject.save!
83
+ embedded_doc.updated_at = Time.now
84
+ end
85
+ its(:changed?) { should be_false }
86
+ end
87
+ end
88
+
89
+ context "embeds_many relationship" do
90
+ context "when adding document" do
91
+ before :each do
92
+ @embedded_doc = TestEmbeddedDocument.new
93
+ subject.many_documents << @embedded_doc
94
+ end
95
+
96
+ its(:changed?) { should be_true }
97
+ its(:children_changed?) { should be_false }
98
+ its(:relations_changed?) { should be_true }
99
+ its(:changed_with_relations?) { should be_true }
100
+ its(:changes_with_relations) { should include(subject.relation_changes) }
101
+
102
+ describe "#relation_changes" do
103
+ it "returns array with differences" do
104
+ expect(subject.relation_changes['many_documents']).to eq([[], [@embedded_doc.attributes]])
105
+ end
106
+ end
107
+ end
108
+
109
+
110
+ context "when removing document" do
111
+ before :each do
112
+ @embedded_doc = TestEmbeddedDocument.new
113
+ subject.many_documents = [@embedded_doc]
114
+ subject.save!
115
+ subject.many_documents.delete @embedded_doc
116
+ end
117
+
118
+ its(:changed?) { should be_true }
119
+ its(:children_changed?) { should be_false }
120
+ its(:relations_changed?) { should be_true }
121
+ its(:changed_with_relations?) { should be_true }
122
+ its(:changes_with_relations) { should include(subject.relation_changes) }
123
+
124
+ describe "#relation_changes" do
125
+ it "returns array with differences" do
126
+ expect(subject.relation_changes['many_documents']).to eq([[@embedded_doc.attributes], []])
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+
133
+ context "has_one relationship" do
134
+ context "when adding document" do
135
+ before :each do
136
+ @related_doc = TestRelatedDocument.new
137
+ subject.one_related = @related_doc
138
+ end
139
+
140
+ its(:changed?) { should be_true }
141
+ its(:children_changed?) { should be_false }
142
+ its(:relations_changed?) { should be_true }
143
+ its(:changed_with_relations?) { should be_true }
144
+ its(:changes_with_relations) { should include(subject.relation_changes) }
145
+
146
+ describe "#relation_changes" do
147
+ it "returns array with differences" do
148
+ expect(subject.relation_changes['one_related']).to eq([nil, {'_id' => @related_doc._id}])
149
+ end
150
+ end
151
+ end
152
+
153
+ context "when removing document" do
154
+ before :each do
155
+ @related_doc = TestRelatedDocument.new
156
+ subject.one_related = @related_doc
157
+ subject.save!
158
+ subject.one_related = nil
159
+ end
160
+
161
+ its(:changed?) { should be_true }
162
+ its(:children_changed?) { should be_false }
163
+ its(:relations_changed?) { should be_true }
164
+ its(:changed_with_relations?) { should be_true }
165
+ its(:changes_with_relations) { should include(subject.relation_changes) }
166
+
167
+ describe "#relation_changes" do
168
+ it "returns array with differences" do
169
+ expect(subject.relation_changes['one_related']).to eq([{'_id' => @related_doc._id}, nil])
170
+ end
171
+ end
172
+ end
173
+
174
+ context "when changing document" do
175
+ before :each do
176
+ @related_doc = TestRelatedDocument.new
177
+ subject.one_related = @related_doc
178
+ subject.save!
179
+ subject.one_related = @another_related_doc = TestRelatedDocument.new
180
+ end
181
+
182
+ its(:changed?) { should be_true }
183
+ its(:children_changed?) { should be_false }
184
+ its(:relations_changed?) { should be_true }
185
+ its(:changed_with_relations?) { should be_true }
186
+ its(:changes_with_relations) { should include(subject.relation_changes) }
187
+
188
+ describe "#relation_changes" do
189
+ it "returns array with differences" do
190
+ expect(subject.relation_changes['one_related']).to eq([{'_id' => @related_doc._id}, {'_id' => @another_related_doc._id}])
191
+ end
192
+ end
193
+ end
194
+
195
+ context "when changing value on referenced document" do
196
+ before :each do
197
+ @related_doc = TestRelatedDocument.new
198
+ subject.one_related = @related_doc
199
+ subject.save!
200
+ subject.one_related.title = "New title"
201
+ end
202
+
203
+ its(:changed?) { should be_false }
204
+ its(:children_changed?) { should be_false }
205
+ its(:relations_changed?) { should be_false }
206
+ its(:changed_with_relations?) { should be_false }
207
+ its(:relation_changes) { should be_empty }
208
+ end
209
+ end
210
+
211
+
212
+ context "has_many relationship" do
213
+ context "when adding document" do
214
+ before :each do
215
+ @related_doc = TestRelatedDocument.new
216
+ subject.many_related << @related_doc
217
+ end
218
+
219
+ its(:changed?) { should be_true }
220
+ its(:children_changed?) { should be_false }
221
+ its(:relations_changed?) { should be_true }
222
+ its(:changed_with_relations?) { should be_true }
223
+ its(:changes_with_relations) { should include(subject.relation_changes) }
224
+
225
+ describe "#relation_changes" do
226
+ it "returns array with differences" do
227
+ expect(subject.relation_changes['many_related']).to eq([[], [{'_id' => @related_doc._id}]])
228
+ end
229
+ end
230
+ end
231
+
232
+ context "when removing document" do
233
+ before :each do
234
+ @related_doc = TestRelatedDocument.new
235
+ subject.many_related << @related_doc
236
+ subject.save!
237
+ subject.many_related.delete @related_doc
238
+ end
239
+
240
+ its(:changed?) { should be_true }
241
+ its(:children_changed?) { should be_false }
242
+ its(:relations_changed?) { should be_true }
243
+ its(:changed_with_relations?) { should be_true }
244
+ its(:changes_with_relations) { should include(subject.relation_changes) }
245
+
246
+ describe "#relation_changes" do
247
+ it "returns array with differences" do
248
+ expect(subject.relation_changes['many_related']).to eq([[{'_id' => @related_doc._id}], []])
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+
255
+ context "has_and_belongs_to_many relationship" do
256
+ context "when adding document" do
257
+ before :each do
258
+ @related_doc = TestRelatedDocument.new
259
+ subject.many_to_many_related << @related_doc
260
+ end
261
+
262
+ its(:changed?) { should be_true }
263
+ its(:children_changed?) { should be_false }
264
+ its(:relations_changed?) { should be_true }
265
+ its(:changed_with_relations?) { should be_true }
266
+ its(:changes_with_relations) { should include(subject.relation_changes) }
267
+
268
+ describe "#relation_changes" do
269
+ it "returns array with differences" do
270
+ expect(subject.relation_changes['many_to_many_related']).to eq([[], [{'_id' => @related_doc._id}]])
271
+ end
272
+ end
273
+ end
274
+
275
+ context "when removing document" do
276
+ before :each do
277
+ @related_doc = TestRelatedDocument.new
278
+ subject.many_to_many_related << @related_doc
279
+ subject.save!
280
+ subject.many_to_many_related.delete @related_doc
281
+ end
282
+
283
+ its(:changed?) { should be_true }
284
+ its(:children_changed?) { should be_false }
285
+ its(:relations_changed?) { should be_true }
286
+ its(:changed_with_relations?) { should be_true }
287
+ its(:changes_with_relations) { should include(subject.relation_changes) }
288
+
289
+ describe "#relation_changes" do
290
+ it "returns array with differences" do
291
+ expect(subject.relation_changes['many_to_many_related']).to eq([[{'_id' => @related_doc._id}], []])
292
+ end
293
+ end
294
+ end
295
+ end
296
+
297
+
298
+ context "belongs_to relationship" do
299
+ subject { TestRelatedDocument.create }
300
+
301
+ context "when adding document" do
302
+ before :each do
303
+ @doc = TestDocument.create
304
+ subject.test_document = @doc
305
+ end
306
+
307
+ its(:changed?) { should be_true }
308
+ its(:children_changed?) { should be_false }
309
+ its(:relations_changed?) { should be_true }
310
+ its(:changed_with_relations?) { should be_true }
311
+ its(:changes_with_relations) { should include(subject.relation_changes) }
312
+
313
+ describe "#relation_changes" do
314
+ it "returns array with differences" do
315
+ expect(subject.relation_changes['test_document']).to eq([nil, {'test_document_id' => @doc._id}])
316
+ end
317
+ end
318
+ end
319
+
320
+ context "when removing document" do
321
+ before :each do
322
+ @doc = TestDocument.create
323
+ subject.test_document = @doc
324
+ subject.save!
325
+ subject.test_document = nil
326
+ end
327
+
328
+ its(:changed?) { should be_true }
329
+ its(:children_changed?) { should be_false }
330
+ its(:relations_changed?) { should be_true }
331
+ its(:changed_with_relations?) { should be_true }
332
+ its(:changes_with_relations) { should include(subject.relation_changes) }
333
+
334
+ describe "#relation_changes" do
335
+ it "returns array with differences" do
336
+ expect(subject.relation_changes['test_document']).to eq([{'test_document_id' => @doc._id}, nil])
337
+ end
338
+ end
339
+ end
340
+ end
341
+
342
+
343
+ describe ".track_relation?" do
344
+ context "with only options" do
345
+ it "do tracks only specified relations" do
346
+ expect(TestDocumentWithOnlyOption.track_relation? :many_documents).to be_true
347
+ expect(TestDocumentWithOnlyOption.track_relation? :one_related).to be_false
348
+ end
349
+ end
350
+
351
+ context "with except options" do
352
+ it "do no track excluded relations" do
353
+ expect(TestDocumentWithExceptOption.track_relation? 'many_documents').to be_false
354
+ expect(TestDocumentWithExceptOption.track_relation? 'one_related').to be_true
355
+ end
356
+ end
357
+ end
358
+
359
+
360
+ describe "by befault the versions relation is not tracked" do
361
+ context "when not called 'relations_dirty_tracking'" do
362
+ it "'versions' is excluded from tracing" do
363
+ expect(Class.new(TestDocument).relations_dirty_tracking_options[:except]).to include('versions')
364
+ end
365
+ end
366
+
367
+ context "when called 'relations_dirty_tracking' with only" do
368
+ it "'versions' is excluded from tracing" do
369
+ klass = Class.new(TestDocument) { relations_dirty_tracking(only: 'foobar') }
370
+ expect(klass.relations_dirty_tracking_options[:except]).to include('versions')
371
+ end
372
+ end
373
+
374
+ context "when called 'relations_dirty_tracking' with except" do
375
+ it "'versions' is excluded from tracing" do
376
+ klass = Class.new(TestDocument) { relations_dirty_tracking(except: 'foobar') }
377
+ expect(klass.relations_dirty_tracking_options[:except]).to include('versions')
378
+ expect(klass.relations_dirty_tracking_options[:except]).to include('foobar')
379
+ end
380
+ end
381
+ end
382
+ end
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'mongoid'
4
+ require 'mongoid/relations_dirty_tracking'
5
+
6
+ require 'rspec'
7
+
8
+ class TestDocument
9
+ include Mongoid::Document
10
+ include Mongoid::RelationsDirtyTracking
11
+
12
+ embeds_one :one_document, class_name: 'TestEmbeddedDocument'
13
+ embeds_many :many_documents, class_name: 'TestEmbeddedDocument'
14
+
15
+ has_one :one_related, class_name: 'TestRelatedDocument'
16
+ has_many :many_related, class_name: 'TestRelatedDocument'
17
+ has_and_belongs_to_many :many_to_many_related, class_name: 'TestRelatedDocument'
18
+ end
19
+
20
+ class TestEmbeddedDocument
21
+ include Mongoid::Document
22
+
23
+ embedded_in :test_document
24
+
25
+ field :title, type: String
26
+ end
27
+
28
+ class TestRelatedDocument
29
+ include Mongoid::Document
30
+ include Mongoid::RelationsDirtyTracking
31
+
32
+ belongs_to :test_document, inverse_of: :one_related
33
+
34
+ field :title, type: String
35
+ end
36
+
37
+ class TestDocumentWithOnlyOption
38
+ include Mongoid::Document
39
+ include Mongoid::RelationsDirtyTracking
40
+
41
+ embeds_many :many_documents, class_name: 'TestEmbeddedDocument'
42
+ has_one :one_related, class_name: 'TestRelatedDocument'
43
+
44
+ relations_dirty_tracking only: :many_documents
45
+ end
46
+
47
+ class TestDocumentWithExceptOption
48
+ include Mongoid::Document
49
+ include Mongoid::RelationsDirtyTracking
50
+
51
+ embeds_many :many_documents, class_name: 'TestEmbeddedDocument'
52
+ has_one :one_related, class_name: 'TestRelatedDocument'
53
+
54
+ relations_dirty_tracking except: 'many_documents'
55
+ end
56
+
57
+
58
+ Mongoid.configure do |config|
59
+ config.connect_to('mongoid_relations_dirty_tracking_test')
60
+ end
61
+
62
+ RSpec.configure do |config|
63
+ config.mock_with :rspec
64
+ config.after(:each) { Mongoid.purge! }
65
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongoid_relations_dirty_tracking
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - David Sevcik
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mongoid
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.1.0
34
+ - - <
35
+ - !ruby/object:Gem::Version
36
+ version: '4.0'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 3.1.0
44
+ - - <
45
+ - !ruby/object:Gem::Version
46
+ version: '4.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: '1.3'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ~>
80
+ - !ruby/object:Gem::Version
81
+ version: '2.8'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ version: '2.8'
89
+ - !ruby/object:Gem::Dependency
90
+ name: pry
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ description: Mongoid extension for tracking changes on document relations
104
+ email:
105
+ - david.sevcik@gmail.com
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - .gitignore
111
+ - Gemfile
112
+ - LICENSE.txt
113
+ - README.md
114
+ - Rakefile
115
+ - lib/mongoid/relations_dirty_tracking.rb
116
+ - lib/mongoid/relations_dirty_tracking/version.rb
117
+ - lib/mongoid/relations_dirty_tracking/versioning.rb
118
+ - lib/mongoid_relations_dirty_tracking.rb
119
+ - mongoid_relations_dirty_tracking.gemspec
120
+ - spec/lib/mongoid/relations_dirty_tracking_spec.rb
121
+ - spec/spec_helper.rb
122
+ homepage: http://github.com/versative/relations_dirty_tracking
123
+ licenses:
124
+ - MIT
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - '>='
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.1.11
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Mongoid extension for tracking changes on document relations
146
+ test_files:
147
+ - spec/lib/mongoid/relations_dirty_tracking_spec.rb
148
+ - spec/spec_helper.rb