mongoid 8.0.7 → 8.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +65 -41
- data/lib/mongoid/association/accessors.rb +5 -1
- data/lib/mongoid/association/eager_loadable.rb +3 -0
- data/lib/mongoid/atomic.rb +9 -7
- data/lib/mongoid/config.rb +10 -0
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -1
- data/lib/mongoid/document.rb +8 -1
- data/lib/mongoid/fields.rb +11 -6
- data/lib/mongoid/interceptable.rb +10 -8
- data/lib/mongoid/timestamps/created.rb +8 -1
- data/lib/mongoid/traversable.rb +12 -0
- data/lib/mongoid/validatable/associated.rb +98 -17
- data/lib/mongoid/validatable.rb +8 -0
- data/lib/mongoid/version.rb +1 -1
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +40 -0
- data/spec/integration/callbacks_models.rb +37 -0
- data/spec/integration/callbacks_spec.rb +27 -0
- data/spec/mongoid/association/eager_spec.rb +24 -2
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +4 -0
- data/spec/mongoid/association_spec.rb +60 -0
- data/spec/mongoid/document_spec.rb +27 -0
- data/spec/mongoid/interceptable_spec.rb +100 -0
- data/spec/mongoid/interceptable_spec_models.rb +51 -111
- data/spec/mongoid/serializable_spec.rb +14 -14
- data/spec/mongoid/timestamps/created_spec.rb +23 -0
- data/spec/mongoid/validatable/associated_spec.rb +27 -34
- data/spec/support/models/name.rb +10 -0
- metadata +4 -80
- checksums.yaml.gz.sig +0 -0
- data/spec/shared/LICENSE +0 -20
- data/spec/shared/bin/get-mongodb-download-url +0 -17
- data/spec/shared/bin/s3-copy +0 -45
- data/spec/shared/bin/s3-upload +0 -69
- data/spec/shared/lib/mrss/child_process_helper.rb +0 -80
- data/spec/shared/lib/mrss/cluster_config.rb +0 -231
- data/spec/shared/lib/mrss/constraints.rb +0 -378
- data/spec/shared/lib/mrss/docker_runner.rb +0 -298
- data/spec/shared/lib/mrss/eg_config_utils.rb +0 -51
- data/spec/shared/lib/mrss/event_subscriber.rb +0 -210
- data/spec/shared/lib/mrss/lite_constraints.rb +0 -238
- data/spec/shared/lib/mrss/server_version_registry.rb +0 -113
- data/spec/shared/lib/mrss/session_registry.rb +0 -69
- data/spec/shared/lib/mrss/session_registry_legacy.rb +0 -60
- data/spec/shared/lib/mrss/spec_organizer.rb +0 -179
- data/spec/shared/lib/mrss/utils.rb +0 -37
- data/spec/shared/share/Dockerfile.erb +0 -321
- data/spec/shared/share/haproxy-1.conf +0 -16
- data/spec/shared/share/haproxy-2.conf +0 -17
- data/spec/shared/shlib/config.sh +0 -27
- data/spec/shared/shlib/distro.sh +0 -74
- data/spec/shared/shlib/server.sh +0 -416
- data/spec/shared/shlib/set_env.sh +0 -169
- data.tar.gz.sig +0 -4
- metadata.gz.sig +0 -0
@@ -467,4 +467,31 @@ describe 'callbacks integration tests' do
|
|
467
467
|
expect { book.save! }.not_to raise_error(SystemStackError)
|
468
468
|
end
|
469
469
|
end
|
470
|
+
|
471
|
+
context 'nested embedded documents' do
|
472
|
+
config_override :prevent_multiple_calls_of_embedded_callbacks, true
|
473
|
+
|
474
|
+
let(:logger) { Array.new }
|
475
|
+
|
476
|
+
let(:root) do
|
477
|
+
Root.new(
|
478
|
+
embedded_once: [
|
479
|
+
EmbeddedOnce.new(
|
480
|
+
embedded_twice: [EmbeddedTwice.new]
|
481
|
+
)
|
482
|
+
]
|
483
|
+
)
|
484
|
+
end
|
485
|
+
|
486
|
+
before(:each) do
|
487
|
+
root.logger = logger
|
488
|
+
root.embedded_once.first.logger = logger
|
489
|
+
root.embedded_once.first.embedded_twice.first.logger = logger
|
490
|
+
end
|
491
|
+
|
492
|
+
it 'runs callbacks in the correct order' do
|
493
|
+
root.save!
|
494
|
+
expect(logger).to eq(%i[embedded_twice embedded_once root])
|
495
|
+
end
|
496
|
+
end
|
470
497
|
end
|
@@ -14,14 +14,36 @@ describe Mongoid::Association::EagerLoadable do
|
|
14
14
|
Mongoid::Contextual::Mongo.new(criteria)
|
15
15
|
end
|
16
16
|
|
17
|
+
let(:association_host) { Account }
|
18
|
+
|
17
19
|
let(:inclusions) do
|
18
20
|
includes.map do |key|
|
19
|
-
|
21
|
+
association_host.reflect_on_association(key)
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
25
|
let(:doc) { criteria.first }
|
24
26
|
|
27
|
+
context 'when root is an STI subclass' do
|
28
|
+
# Driver has_one Vehicle
|
29
|
+
# Vehicle belongs_to Driver
|
30
|
+
# Truck is a Vehicle
|
31
|
+
|
32
|
+
before do
|
33
|
+
Driver.create!(vehicle: Truck.new)
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:criteria) { Truck.all }
|
37
|
+
let(:includes) { %i[ driver ] }
|
38
|
+
let(:association_host) { Truck }
|
39
|
+
|
40
|
+
it 'preloads the driver' do
|
41
|
+
expect(doc.ivar(:driver)).to be false
|
42
|
+
context.preload(inclusions, [ doc ])
|
43
|
+
expect(doc.ivar(:driver)).to be == Driver.first
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
25
47
|
context "when belongs_to" do
|
26
48
|
|
27
49
|
let!(:account) do
|
@@ -42,7 +64,7 @@ describe Mongoid::Association::EagerLoadable do
|
|
42
64
|
it "preloads the parent" do
|
43
65
|
expect(doc.ivar(:person)).to be false
|
44
66
|
context.preload(inclusions, [doc])
|
45
|
-
expect(doc.ivar(:person)).to
|
67
|
+
expect(doc.ivar(:person)).to be == person
|
46
68
|
end
|
47
69
|
end
|
48
70
|
|
@@ -27,6 +27,10 @@ describe Mongoid::Association::Embedded::EmbedsMany do
|
|
27
27
|
expect(legislator.attributes.keys).to eq(['_id', 'a'])
|
28
28
|
end
|
29
29
|
|
30
|
+
it 'allows accessing the parent' do
|
31
|
+
expect { legislator.congress }.not_to raise_error
|
32
|
+
end
|
33
|
+
|
30
34
|
context 'when using only with $' do
|
31
35
|
before do
|
32
36
|
Patient.destroy_all
|
@@ -100,6 +100,66 @@ describe Mongoid::Association do
|
|
100
100
|
expect(name).to_not be_an_embedded_many
|
101
101
|
end
|
102
102
|
end
|
103
|
+
|
104
|
+
context "when validation depends on association" do
|
105
|
+
before(:all) do
|
106
|
+
class Author
|
107
|
+
include Mongoid::Document
|
108
|
+
embeds_many :books, cascade_callbacks: true
|
109
|
+
field :condition, type: Boolean
|
110
|
+
end
|
111
|
+
|
112
|
+
class Book
|
113
|
+
include Mongoid::Document
|
114
|
+
embedded_in :author
|
115
|
+
validate :parent_condition_is_not_true
|
116
|
+
|
117
|
+
def parent_condition_is_not_true
|
118
|
+
return unless author&.condition
|
119
|
+
errors.add :base, "Author condition is true."
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
Author.delete_all
|
124
|
+
Book.delete_all
|
125
|
+
end
|
126
|
+
|
127
|
+
let(:author) { Author.new }
|
128
|
+
let(:book) { Book.new }
|
129
|
+
|
130
|
+
context "when author is not persisted" do
|
131
|
+
it "is valid without books" do
|
132
|
+
expect(author.valid?).to be true
|
133
|
+
end
|
134
|
+
|
135
|
+
it "is valid with a book" do
|
136
|
+
author.books << book
|
137
|
+
expect(author.valid?).to be true
|
138
|
+
end
|
139
|
+
|
140
|
+
it "is not valid when condition is true with a book" do
|
141
|
+
author.condition = true
|
142
|
+
author.books << book
|
143
|
+
expect(author.valid?).to be false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "when author is persisted" do
|
148
|
+
before do
|
149
|
+
author.books << book
|
150
|
+
author.save
|
151
|
+
end
|
152
|
+
|
153
|
+
it "remains valid initially" do
|
154
|
+
expect(author.valid?).to be true
|
155
|
+
end
|
156
|
+
|
157
|
+
it "becomes invalid when condition is set to true" do
|
158
|
+
author.update_attributes(condition: true)
|
159
|
+
expect(author.valid?).to be false
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
103
163
|
end
|
104
164
|
|
105
165
|
describe "#embedded_one?" do
|
@@ -591,6 +591,33 @@ describe Mongoid::Document do
|
|
591
591
|
expect(person.as_document["addresses"].first).to have_key(:locations)
|
592
592
|
end
|
593
593
|
|
594
|
+
context 'when modifying the returned object' do
|
595
|
+
let(:record) do
|
596
|
+
RootCategory.create(categories: [{ name: 'tests' }]).reload
|
597
|
+
end
|
598
|
+
|
599
|
+
shared_examples_for 'an object with protected internal state' do
|
600
|
+
it 'does not expose internal state' do
|
601
|
+
before_change = record.as_document.dup
|
602
|
+
record.categories.first.name = 'things'
|
603
|
+
after_change = record.as_document
|
604
|
+
expect(before_change['categories'].first['name']).not_to eq('things')
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
context 'when legacy_attributes is true' do
|
609
|
+
config_override :legacy_attributes, true
|
610
|
+
|
611
|
+
it_behaves_like 'an object with protected internal state'
|
612
|
+
end
|
613
|
+
|
614
|
+
context 'when legacy_attributes is false' do
|
615
|
+
config_override :legacy_attributes, false
|
616
|
+
|
617
|
+
it_behaves_like 'an object with protected internal state'
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
594
621
|
context "with relation define store_as option in embeded_many" do
|
595
622
|
|
596
623
|
let!(:phone) do
|
@@ -388,6 +388,86 @@ describe Mongoid::Interceptable do
|
|
388
388
|
end
|
389
389
|
end
|
390
390
|
end
|
391
|
+
|
392
|
+
context 'with embedded grandchildren' do
|
393
|
+
IS = InterceptableSpec
|
394
|
+
|
395
|
+
config_override :prevent_multiple_calls_of_embedded_callbacks, true
|
396
|
+
|
397
|
+
context 'when creating' do
|
398
|
+
let(:registry) { IS::CallbackRegistry.new(only: %i[ before_save ]) }
|
399
|
+
|
400
|
+
let(:expected_calls) do
|
401
|
+
[
|
402
|
+
# the parent
|
403
|
+
[ IS::CbParent, :before_save ],
|
404
|
+
|
405
|
+
# the immediate child of the parent
|
406
|
+
[ IS::CbCascadedNode, :before_save ],
|
407
|
+
|
408
|
+
# the grandchild of the parent
|
409
|
+
[ IS::CbCascadedNode, :before_save ],
|
410
|
+
]
|
411
|
+
end
|
412
|
+
|
413
|
+
let!(:parent) do
|
414
|
+
parent = IS::CbParent.new(registry)
|
415
|
+
child = IS::CbCascadedNode.new(registry)
|
416
|
+
grandchild = IS::CbCascadedNode.new(registry)
|
417
|
+
|
418
|
+
child.cb_cascaded_nodes = [ grandchild ]
|
419
|
+
parent.cb_cascaded_nodes = [ child ]
|
420
|
+
|
421
|
+
parent.tap(&:save)
|
422
|
+
end
|
423
|
+
|
424
|
+
it 'should cascade callbacks to grandchildren' do
|
425
|
+
expect(registry.calls).to be == expected_calls
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
context 'when updating' do
|
430
|
+
let(:registry) { IS::CallbackRegistry.new(only: %i[ before_update ]) }
|
431
|
+
|
432
|
+
let(:expected_calls) do
|
433
|
+
[
|
434
|
+
# the parent
|
435
|
+
[ IS::CbParent, :before_update ],
|
436
|
+
|
437
|
+
# the immediate child of the parent
|
438
|
+
[ IS::CbCascadedNode, :before_update ],
|
439
|
+
|
440
|
+
# the grandchild of the parent
|
441
|
+
[ IS::CbCascadedNode, :before_update ],
|
442
|
+
]
|
443
|
+
end
|
444
|
+
|
445
|
+
let!(:parent) do
|
446
|
+
parent = IS::CbParent.new(nil)
|
447
|
+
child = IS::CbCascadedNode.new(nil)
|
448
|
+
grandchild = IS::CbCascadedNode.new(nil)
|
449
|
+
|
450
|
+
child.cb_cascaded_nodes = [ grandchild ]
|
451
|
+
parent.cb_cascaded_nodes = [ child ]
|
452
|
+
|
453
|
+
parent.save
|
454
|
+
|
455
|
+
parent.callback_registry = registry
|
456
|
+
child.callback_registry = registry
|
457
|
+
grandchild.callback_registry = registry
|
458
|
+
|
459
|
+
parent.name = 'updated'
|
460
|
+
child.name = 'updated'
|
461
|
+
grandchild.name = 'updated'
|
462
|
+
|
463
|
+
parent.tap(&:save)
|
464
|
+
end
|
465
|
+
|
466
|
+
it 'should cascade callbacks to grandchildren' do
|
467
|
+
expect(registry.calls).to be == expected_calls
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
391
471
|
end
|
392
472
|
|
393
473
|
describe ".before_destroy" do
|
@@ -578,6 +658,26 @@ describe Mongoid::Interceptable do
|
|
578
658
|
band.notes.push(note)
|
579
659
|
record.notes.push(note)
|
580
660
|
end
|
661
|
+
|
662
|
+
context "when saving the root" do
|
663
|
+
context 'with prevent_multiple_calls_of_embedded_callbacks enabled' do
|
664
|
+
config_override :prevent_multiple_calls_of_embedded_callbacks, true
|
665
|
+
|
666
|
+
it "executes the callbacks only once for each document" do
|
667
|
+
expect(note).to receive(:update_saved).once
|
668
|
+
band.save!
|
669
|
+
end
|
670
|
+
end
|
671
|
+
|
672
|
+
context 'with prevent_multiple_calls_of_embedded_callbacks disabled' do
|
673
|
+
config_override :prevent_multiple_calls_of_embedded_callbacks, false
|
674
|
+
|
675
|
+
it "executes the callbacks once for each ember" do
|
676
|
+
expect(note).to receive(:update_saved).twice
|
677
|
+
band.save!
|
678
|
+
end
|
679
|
+
end
|
680
|
+
end
|
581
681
|
end
|
582
682
|
end
|
583
683
|
|
@@ -1,13 +1,19 @@
|
|
1
1
|
module InterceptableSpec
|
2
2
|
class CallbackRegistry
|
3
|
-
def initialize
|
3
|
+
def initialize(only: [])
|
4
4
|
@calls = []
|
5
|
+
@only = only
|
5
6
|
end
|
6
7
|
|
7
8
|
def record_call(cls, cb)
|
9
|
+
return unless @only.empty? || @only.any? { |pat| pat == cb }
|
8
10
|
@calls << [cls, cb]
|
9
11
|
end
|
10
12
|
|
13
|
+
def reset!
|
14
|
+
@calls.clear
|
15
|
+
end
|
16
|
+
|
11
17
|
attr_reader :calls
|
12
18
|
end
|
13
19
|
|
@@ -15,6 +21,8 @@ module InterceptableSpec
|
|
15
21
|
extend ActiveSupport::Concern
|
16
22
|
|
17
23
|
included do
|
24
|
+
field :name, type: String
|
25
|
+
|
18
26
|
%i(
|
19
27
|
validation save create update
|
20
28
|
).each do |what|
|
@@ -34,196 +42,128 @@ module InterceptableSpec
|
|
34
42
|
end
|
35
43
|
end
|
36
44
|
end
|
37
|
-
end
|
38
45
|
|
39
|
-
|
40
|
-
include Mongoid::Document
|
41
|
-
|
42
|
-
has_one :child, autosave: true, class_name: "CbHasOneChild", inverse_of: :parent
|
46
|
+
attr_accessor :callback_registry
|
43
47
|
|
44
|
-
def initialize(callback_registry)
|
48
|
+
def initialize(callback_registry, *args, **kwargs)
|
45
49
|
@callback_registry = callback_registry
|
46
|
-
super()
|
50
|
+
super(*args, **kwargs)
|
47
51
|
end
|
52
|
+
end
|
48
53
|
|
49
|
-
|
50
|
-
|
54
|
+
module RootInsertable
|
51
55
|
def insert_as_root
|
52
56
|
@callback_registry&.record_call(self.class, :insert_into_database)
|
53
57
|
super
|
54
58
|
end
|
59
|
+
end
|
55
60
|
|
61
|
+
class CbHasOneParent
|
62
|
+
include Mongoid::Document
|
56
63
|
include CallbackTracking
|
64
|
+
include RootInsertable
|
65
|
+
|
66
|
+
has_one :child, autosave: true, class_name: "CbHasOneChild", inverse_of: :parent
|
57
67
|
end
|
58
68
|
|
59
69
|
class CbHasOneChild
|
60
70
|
include Mongoid::Document
|
71
|
+
include CallbackTracking
|
61
72
|
|
62
73
|
belongs_to :parent, class_name: "CbHasOneParent", inverse_of: :child
|
63
|
-
|
64
|
-
def initialize(callback_registry)
|
65
|
-
@callback_registry = callback_registry
|
66
|
-
super()
|
67
|
-
end
|
68
|
-
|
69
|
-
attr_accessor :callback_registry
|
70
|
-
|
71
|
-
include CallbackTracking
|
72
74
|
end
|
73
75
|
|
74
76
|
class CbHasManyParent
|
75
77
|
include Mongoid::Document
|
78
|
+
include CallbackTracking
|
79
|
+
include RootInsertable
|
76
80
|
|
77
81
|
has_many :children, autosave: true, class_name: "CbHasManyChild", inverse_of: :parent
|
78
|
-
|
79
|
-
def initialize(callback_registry)
|
80
|
-
@callback_registry = callback_registry
|
81
|
-
super()
|
82
|
-
end
|
83
|
-
|
84
|
-
attr_accessor :callback_registry
|
85
|
-
|
86
|
-
def insert_as_root
|
87
|
-
@callback_registry&.record_call(self.class, :insert_into_database)
|
88
|
-
super
|
89
|
-
end
|
90
|
-
|
91
|
-
include CallbackTracking
|
92
82
|
end
|
93
83
|
|
94
84
|
class CbHasManyChild
|
95
85
|
include Mongoid::Document
|
86
|
+
include CallbackTracking
|
96
87
|
|
97
88
|
belongs_to :parent, class_name: "CbHasManyParent", inverse_of: :children
|
98
|
-
|
99
|
-
def initialize(callback_registry)
|
100
|
-
@callback_registry = callback_registry
|
101
|
-
super()
|
102
|
-
end
|
103
|
-
|
104
|
-
attr_accessor :callback_registry
|
105
|
-
|
106
|
-
include CallbackTracking
|
107
89
|
end
|
108
90
|
|
109
91
|
class CbEmbedsOneParent
|
110
92
|
include Mongoid::Document
|
93
|
+
include CallbackTracking
|
94
|
+
include RootInsertable
|
111
95
|
|
112
96
|
field :name
|
113
97
|
|
114
98
|
embeds_one :child, cascade_callbacks: true, class_name: "CbEmbedsOneChild", inverse_of: :parent
|
115
|
-
|
116
|
-
def initialize(callback_registry)
|
117
|
-
@callback_registry = callback_registry
|
118
|
-
super()
|
119
|
-
end
|
120
|
-
|
121
|
-
attr_accessor :callback_registry
|
122
|
-
|
123
|
-
def insert_as_root
|
124
|
-
@callback_registry&.record_call(self.class, :insert_into_database)
|
125
|
-
super
|
126
|
-
end
|
127
|
-
|
128
|
-
include CallbackTracking
|
129
99
|
end
|
130
100
|
|
131
101
|
class CbEmbedsOneChild
|
132
102
|
include Mongoid::Document
|
103
|
+
include CallbackTracking
|
133
104
|
|
134
105
|
field :age
|
135
106
|
|
136
107
|
embedded_in :parent, class_name: "CbEmbedsOneParent", inverse_of: :child
|
137
|
-
|
138
|
-
def initialize(callback_registry)
|
139
|
-
@callback_registry = callback_registry
|
140
|
-
super()
|
141
|
-
end
|
142
|
-
|
143
|
-
attr_accessor :callback_registry
|
144
|
-
|
145
|
-
include CallbackTracking
|
146
108
|
end
|
147
109
|
|
148
110
|
class CbEmbedsManyParent
|
149
111
|
include Mongoid::Document
|
112
|
+
include CallbackTracking
|
113
|
+
include RootInsertable
|
150
114
|
|
151
115
|
embeds_many :children, cascade_callbacks: true, class_name: "CbEmbedsManyChild", inverse_of: :parent
|
152
|
-
|
153
|
-
def initialize(callback_registry)
|
154
|
-
@callback_registry = callback_registry
|
155
|
-
super()
|
156
|
-
end
|
157
|
-
|
158
|
-
attr_accessor :callback_registry
|
159
|
-
|
160
|
-
def insert_as_root
|
161
|
-
@callback_registry&.record_call(self.class, :insert_into_database)
|
162
|
-
super
|
163
|
-
end
|
164
|
-
|
165
|
-
include CallbackTracking
|
166
116
|
end
|
167
117
|
|
168
118
|
class CbEmbedsManyChild
|
169
119
|
include Mongoid::Document
|
120
|
+
include CallbackTracking
|
170
121
|
|
171
122
|
embedded_in :parent, class_name: "CbEmbedsManyParent", inverse_of: :children
|
172
|
-
|
173
|
-
def initialize(callback_registry)
|
174
|
-
@callback_registry = callback_registry
|
175
|
-
super()
|
176
|
-
end
|
177
|
-
|
178
|
-
attr_accessor :callback_registry
|
179
|
-
|
180
|
-
include CallbackTracking
|
181
123
|
end
|
182
124
|
|
183
125
|
class CbParent
|
184
126
|
include Mongoid::Document
|
185
|
-
|
186
|
-
def initialize(callback_registry)
|
187
|
-
@callback_registry = callback_registry
|
188
|
-
super()
|
189
|
-
end
|
190
|
-
|
191
|
-
attr_accessor :callback_registry
|
127
|
+
include CallbackTracking
|
192
128
|
|
193
129
|
embeds_many :cb_children
|
194
130
|
embeds_many :cb_cascaded_children, cascade_callbacks: true
|
195
|
-
|
196
|
-
include CallbackTracking
|
131
|
+
embeds_many :cb_cascaded_nodes, cascade_callbacks: true, as: :parent
|
197
132
|
end
|
198
133
|
|
199
134
|
class CbChild
|
200
135
|
include Mongoid::Document
|
136
|
+
include CallbackTracking
|
201
137
|
|
202
138
|
embedded_in :cb_parent
|
203
|
-
|
204
|
-
def initialize(callback_registry, options)
|
205
|
-
@callback_registry = callback_registry
|
206
|
-
super(options)
|
207
|
-
end
|
208
|
-
|
209
|
-
attr_accessor :callback_registry
|
210
|
-
|
211
|
-
include CallbackTracking
|
212
139
|
end
|
213
140
|
|
214
141
|
class CbCascadedChild
|
215
142
|
include Mongoid::Document
|
143
|
+
include CallbackTracking
|
216
144
|
|
217
145
|
embedded_in :cb_parent
|
218
146
|
|
219
|
-
|
220
|
-
@callback_registry = callback_registry
|
221
|
-
super(options)
|
222
|
-
end
|
147
|
+
before_save :test_mongoid_state
|
223
148
|
|
224
|
-
|
149
|
+
private
|
150
|
+
|
151
|
+
# Helps test that cascading child callbacks have access to the Mongoid
|
152
|
+
# state objects; if the implementation uses fiber-local (instead of truly
|
153
|
+
# thread-local) variables, the related tests will fail because the
|
154
|
+
# cascading child callbacks use fibers to linearize the recursion.
|
155
|
+
def test_mongoid_state
|
156
|
+
Mongoid::Threaded.stack('interceptable').push(self)
|
157
|
+
end
|
158
|
+
end
|
225
159
|
|
160
|
+
class CbCascadedNode
|
161
|
+
include Mongoid::Document
|
226
162
|
include CallbackTracking
|
163
|
+
|
164
|
+
embedded_in :parent, polymorphic: true
|
165
|
+
|
166
|
+
embeds_many :cb_cascaded_nodes, cascade_callbacks: true, as: :parent
|
227
167
|
end
|
228
168
|
end
|
229
169
|
|
@@ -528,13 +528,13 @@ describe Mongoid::Serializable do
|
|
528
528
|
end
|
529
529
|
|
530
530
|
it "includes the first relation" do
|
531
|
-
expect(relation_hash[0]).to include
|
532
|
-
{ "_id" => "kudamm", "street" => "Kudamm" }
|
531
|
+
expect(relation_hash[0]).to include(
|
532
|
+
{ "_id" => "kudamm", "street" => "Kudamm" })
|
533
533
|
end
|
534
534
|
|
535
535
|
it "includes the second relation" do
|
536
|
-
expect(relation_hash[1]).to include
|
537
|
-
{ "_id" => "tauentzienstr", "street" => "Tauentzienstr" }
|
536
|
+
expect(relation_hash[1]).to include(
|
537
|
+
{ "_id" => "tauentzienstr", "street" => "Tauentzienstr" })
|
538
538
|
end
|
539
539
|
end
|
540
540
|
|
@@ -545,13 +545,13 @@ describe Mongoid::Serializable do
|
|
545
545
|
end
|
546
546
|
|
547
547
|
it "includes the first relation" do
|
548
|
-
expect(relation_hash[0]).to include
|
549
|
-
{ "_id" => "kudamm", "street" => "Kudamm" }
|
548
|
+
expect(relation_hash[0]).to include(
|
549
|
+
{ "_id" => "kudamm", "street" => "Kudamm" })
|
550
550
|
end
|
551
551
|
|
552
552
|
it "includes the second relation" do
|
553
|
-
expect(relation_hash[1]).to include
|
554
|
-
{ "_id" => "tauentzienstr", "street" => "Tauentzienstr" }
|
553
|
+
expect(relation_hash[1]).to include(
|
554
|
+
{ "_id" => "tauentzienstr", "street" => "Tauentzienstr" })
|
555
555
|
end
|
556
556
|
end
|
557
557
|
|
@@ -670,8 +670,8 @@ describe Mongoid::Serializable do
|
|
670
670
|
end
|
671
671
|
|
672
672
|
it "includes the specified relation" do
|
673
|
-
expect(relation_hash).to include
|
674
|
-
{ "_id" => "
|
673
|
+
expect(relation_hash).to include(
|
674
|
+
{ "_id" => "Leo-Marvin", "first_name" => "Leo", "last_name" => "Marvin" })
|
675
675
|
end
|
676
676
|
end
|
677
677
|
|
@@ -682,8 +682,8 @@ describe Mongoid::Serializable do
|
|
682
682
|
end
|
683
683
|
|
684
684
|
it "includes the specified relation" do
|
685
|
-
expect(relation_hash).to include
|
686
|
-
{ "_id" => "
|
685
|
+
expect(relation_hash).to include(
|
686
|
+
{ "_id" => "Leo-Marvin", "first_name" => "Leo", "last_name" => "Marvin" })
|
687
687
|
end
|
688
688
|
end
|
689
689
|
|
@@ -694,8 +694,8 @@ describe Mongoid::Serializable do
|
|
694
694
|
end
|
695
695
|
|
696
696
|
it "includes the specified relation sans exceptions" do
|
697
|
-
expect(relation_hash).to include
|
698
|
-
{ "first_name" => "Leo", "last_name" => "Marvin" }
|
697
|
+
expect(relation_hash).to include(
|
698
|
+
{ "first_name" => "Leo", "last_name" => "Marvin" })
|
699
699
|
end
|
700
700
|
end
|
701
701
|
end
|
@@ -43,4 +43,27 @@ describe Mongoid::Timestamps::Created do
|
|
43
43
|
expect(quiz.created_at).to be_within(10).of(Time.now.utc)
|
44
44
|
end
|
45
45
|
end
|
46
|
+
|
47
|
+
context "when the document is destroyed" do
|
48
|
+
let(:book) do
|
49
|
+
Book.create!
|
50
|
+
end
|
51
|
+
|
52
|
+
before do
|
53
|
+
Cover.before_save do
|
54
|
+
destroy if title == "delete me"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
after do
|
59
|
+
Cover.reset_callbacks(:save)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "does not set the created_at timestamp" do
|
63
|
+
book.covers << Cover.new(title: "delete me")
|
64
|
+
expect {
|
65
|
+
book.save
|
66
|
+
}.not_to raise_error
|
67
|
+
end
|
68
|
+
end
|
46
69
|
end
|