mongoid 8.1.8 → 8.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/mongoid/association/eager_loadable.rb +3 -0
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +21 -4
- data/lib/mongoid/interceptable.rb +6 -5
- data/lib/mongoid/timestamps/created.rb +8 -1
- data/lib/mongoid/traversable.rb +12 -0
- data/lib/mongoid/validatable/associated.rb +1 -1
- data/lib/mongoid/version.rb +1 -1
- data/spec/integration/app_spec.rb +4 -0
- data/spec/mongoid/association/eager_spec.rb +24 -2
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +28 -37
- data/spec/mongoid/association_spec.rb +60 -0
- data/spec/mongoid/interceptable_spec.rb +80 -0
- data/spec/mongoid/interceptable_spec_models.rb +47 -111
- data/spec/mongoid/timestamps/created_spec.rb +23 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0937a2d421f6fde901ea6cf6b84f44f3e0881203d907467bb4be6d29af0294be'
|
4
|
+
data.tar.gz: 603cbd46675272938b68ffa596d5cc49f0c2e60b1fe8d09f79100a67b1d06364
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a82445002bf56d4751a0b808a8aa5ff196ff92d057d6fa4230db17819b365df7e0c3fe9abd46ec063c7575e761cdef921d3682c3e37e7105b9e5bd04310e8fa
|
7
|
+
data.tar.gz: 443a3ce79311113369b4adf96302fc457ef6ae69643ab42845b0ee448f61c946820828137b3d6fbfb121386347cfd15ba129c7ded504f43c7ba3a980f7caf3aa
|
@@ -31,6 +31,9 @@ module Mongoid
|
|
31
31
|
docs_map = {}
|
32
32
|
queue = [ klass.to_s ]
|
33
33
|
|
34
|
+
# account for single-collection inheritance
|
35
|
+
queue.push(klass.root_class.to_s) if klass != klass.root_class
|
36
|
+
|
34
37
|
while klass = queue.shift
|
35
38
|
if as = assoc_map.delete(klass)
|
36
39
|
as.each do |assoc|
|
@@ -422,11 +422,28 @@ module Mongoid
|
|
422
422
|
#
|
423
423
|
# @return [ Integer ] The size of the enumerable.
|
424
424
|
def size
|
425
|
-
|
426
|
-
|
427
|
-
|
425
|
+
# If _unloaded is present, then it will match the set of documents
|
426
|
+
# that belong to this association, which have already been persisted
|
427
|
+
# to the database. This set of documents must be considered when
|
428
|
+
# computing the size of the association, along with anything that has
|
429
|
+
# since been added.
|
430
|
+
if _unloaded
|
431
|
+
if _added.any?
|
432
|
+
# Note that _added may include records that _unloaded already
|
433
|
+
# matches. This is the case if the association is assigned an array
|
434
|
+
# of items and some of them were already elements of the association.
|
435
|
+
#
|
436
|
+
# we need to thus make sure _unloaded.count excludes any elements
|
437
|
+
# that already exist in _added.
|
438
|
+
|
439
|
+
count = _unloaded.not(:_id.in => _added.values.map(&:id)).count
|
440
|
+
count + _added.values.count
|
441
|
+
else
|
442
|
+
_unloaded.count
|
443
|
+
end
|
444
|
+
|
428
445
|
else
|
429
|
-
count + _added.
|
446
|
+
_loaded.count + _added.count
|
430
447
|
end
|
431
448
|
end
|
432
449
|
|
@@ -141,9 +141,13 @@ module Mongoid
|
|
141
141
|
# @api private
|
142
142
|
def _mongoid_run_child_callbacks(kind, children: nil, &block)
|
143
143
|
if Mongoid::Config.around_callbacks_for_embeds
|
144
|
-
_mongoid_run_child_callbacks_with_around(kind,
|
144
|
+
_mongoid_run_child_callbacks_with_around(kind,
|
145
|
+
children: children,
|
146
|
+
&block)
|
145
147
|
else
|
146
|
-
_mongoid_run_child_callbacks_without_around(kind,
|
148
|
+
_mongoid_run_child_callbacks_without_around(kind,
|
149
|
+
children: children,
|
150
|
+
&block)
|
147
151
|
end
|
148
152
|
end
|
149
153
|
|
@@ -219,9 +223,6 @@ module Mongoid
|
|
219
223
|
return false if env.halted
|
220
224
|
env.value = !env.halted
|
221
225
|
callback_list << [next_sequence, env]
|
222
|
-
if (grandchildren = child.send(:cascadable_children, kind))
|
223
|
-
_mongoid_run_child_before_callbacks(kind, children: grandchildren, callback_list: callback_list)
|
224
|
-
end
|
225
226
|
end
|
226
227
|
callback_list
|
227
228
|
end
|
@@ -22,13 +22,20 @@ module Mongoid
|
|
22
22
|
# @example Set the created at time.
|
23
23
|
# person.set_created_at
|
24
24
|
def set_created_at
|
25
|
-
if
|
25
|
+
if able_to_set_created_at?
|
26
26
|
time = Time.configured.now
|
27
27
|
self.updated_at = time if is_a?(Updated) && !updated_at_changed?
|
28
28
|
self.created_at = time
|
29
29
|
end
|
30
30
|
clear_timeless_option
|
31
31
|
end
|
32
|
+
|
33
|
+
# Is the created timestamp able to be set?
|
34
|
+
#
|
35
|
+
# @return [ true, false ] If the timestamp can be set.
|
36
|
+
def able_to_set_created_at?
|
37
|
+
!frozen? && !timeless? && !created_at
|
38
|
+
end
|
32
39
|
end
|
33
40
|
end
|
34
41
|
end
|
data/lib/mongoid/traversable.rb
CHANGED
@@ -323,6 +323,18 @@ module Mongoid
|
|
323
323
|
!!(Mongoid::Document > superclass)
|
324
324
|
end
|
325
325
|
|
326
|
+
# Returns the root class of the STI tree that the current
|
327
|
+
# class participates in. If the class is not an STI subclass, this
|
328
|
+
# returns the class itself.
|
329
|
+
#
|
330
|
+
# @return [ Mongoid::Document ] the root of the STI tree
|
331
|
+
def root_class
|
332
|
+
root = self
|
333
|
+
root = root.superclass while root.hereditary?
|
334
|
+
|
335
|
+
root
|
336
|
+
end
|
337
|
+
|
326
338
|
# When inheriting, we want to copy the fields from the parent class and
|
327
339
|
# set the on the child to start, mimicking the behavior of the old
|
328
340
|
# class_inheritable_accessor that was deprecated in Rails edge.
|
@@ -73,7 +73,7 @@ module Mongoid
|
|
73
73
|
# use map.all? instead of just all?, because all? will do short-circuit
|
74
74
|
# evaluation and terminate on the first failed validation.
|
75
75
|
list.map do |value|
|
76
|
-
if value && !value.flagged_for_destroy?
|
76
|
+
if value && !value.flagged_for_destroy?
|
77
77
|
value.validated? ? true : value.valid?
|
78
78
|
else
|
79
79
|
true
|
data/lib/mongoid/version.rb
CHANGED
@@ -16,6 +16,10 @@ describe 'Mongoid application tests' do
|
|
16
16
|
skip 'Set APP_TESTS=1 in environment to run application tests'
|
17
17
|
end
|
18
18
|
|
19
|
+
if SpecConfig.instance.rails_version < '7.1'
|
20
|
+
skip 'App tests require Rails > 7.0 (see https://stackoverflow.com/questions/79360526)'
|
21
|
+
end
|
22
|
+
|
19
23
|
require 'fileutils'
|
20
24
|
require 'mrss/child_process_helper'
|
21
25
|
require 'open-uri'
|
@@ -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
|
|
@@ -1755,43 +1755,6 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
|
|
1755
1755
|
end
|
1756
1756
|
end
|
1757
1757
|
|
1758
|
-
describe "#any?" do
|
1759
|
-
|
1760
|
-
let(:person) do
|
1761
|
-
Person.create!
|
1762
|
-
end
|
1763
|
-
|
1764
|
-
context "when nothing exists on the relation" do
|
1765
|
-
|
1766
|
-
context "when no document is added" do
|
1767
|
-
|
1768
|
-
let!(:sandwich) do
|
1769
|
-
Sandwich.create!
|
1770
|
-
end
|
1771
|
-
|
1772
|
-
it "returns false" do
|
1773
|
-
expect(sandwich.meats.any?).to be false
|
1774
|
-
end
|
1775
|
-
end
|
1776
|
-
|
1777
|
-
context "when the document is destroyed" do
|
1778
|
-
|
1779
|
-
before do
|
1780
|
-
Meat.create!
|
1781
|
-
end
|
1782
|
-
|
1783
|
-
let!(:sandwich) do
|
1784
|
-
Sandwich.create!
|
1785
|
-
end
|
1786
|
-
|
1787
|
-
it "returns false" do
|
1788
|
-
sandwich.destroy
|
1789
|
-
expect(sandwich.meats.any?).to be false
|
1790
|
-
end
|
1791
|
-
end
|
1792
|
-
end
|
1793
|
-
end
|
1794
|
-
|
1795
1758
|
context "when documents have been persisted" do
|
1796
1759
|
|
1797
1760
|
let!(:preference) do
|
@@ -3041,6 +3004,34 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
|
|
3041
3004
|
end
|
3042
3005
|
end
|
3043
3006
|
|
3007
|
+
# MONGOID-5844
|
3008
|
+
#
|
3009
|
+
# Specifically, this tests the case where the association is
|
3010
|
+
# initialized with a single element (so that Proxy#push does not take
|
3011
|
+
# the `concat` route), which causes `reset_unloaded` to be called, which
|
3012
|
+
# sets the `_unloaded` Criteria object to match only the specific element
|
3013
|
+
# that was given.
|
3014
|
+
#
|
3015
|
+
# The issue now is that when the events list is updated to be both events,
|
3016
|
+
# _unloaded matches one of them already, and the other has previously been
|
3017
|
+
# persisted so `new_record?` won't match it. We need to make sure the
|
3018
|
+
# `#size` logic properly accounts for this case.
|
3019
|
+
context 'when documents have been previously persisted' do
|
3020
|
+
let(:person1) { Person.create! }
|
3021
|
+
let(:person2) { Person.create! }
|
3022
|
+
let(:event1) { Event.create!(administrators: [ person1 ]) }
|
3023
|
+
let(:event2) { Event.create!(administrators: [ person2 ]) }
|
3024
|
+
|
3025
|
+
before do
|
3026
|
+
person1.administrated_events = [ event1, event2 ]
|
3027
|
+
end
|
3028
|
+
|
3029
|
+
it 'returns the number of associated documents [MONGOID-5844]' do
|
3030
|
+
expect(person1.administrated_events.to_a.size).to eq(2)
|
3031
|
+
expect(person1.administrated_events.size).to eq(2)
|
3032
|
+
end
|
3033
|
+
end
|
3034
|
+
|
3044
3035
|
context "when documents have not been persisted" do
|
3045
3036
|
|
3046
3037
|
before do
|
@@ -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
|
@@ -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
|
@@ -1,10 +1,12 @@
|
|
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
|
|
@@ -15,6 +17,8 @@ module InterceptableSpec
|
|
15
17
|
extend ActiveSupport::Concern
|
16
18
|
|
17
19
|
included do
|
20
|
+
field :name, type: String
|
21
|
+
|
18
22
|
%i(
|
19
23
|
validation save create update
|
20
24
|
).each do |what|
|
@@ -34,196 +38,128 @@ module InterceptableSpec
|
|
34
38
|
end
|
35
39
|
end
|
36
40
|
end
|
37
|
-
end
|
38
41
|
|
39
|
-
|
40
|
-
include Mongoid::Document
|
41
|
-
|
42
|
-
has_one :child, autosave: true, class_name: "CbHasOneChild", inverse_of: :parent
|
42
|
+
attr_accessor :callback_registry
|
43
43
|
|
44
|
-
def initialize(callback_registry)
|
44
|
+
def initialize(callback_registry, *args, **kwargs)
|
45
45
|
@callback_registry = callback_registry
|
46
|
-
super()
|
46
|
+
super(*args, **kwargs)
|
47
47
|
end
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
module RootInsertable
|
51
51
|
def insert_as_root
|
52
52
|
@callback_registry&.record_call(self.class, :insert_into_database)
|
53
53
|
super
|
54
54
|
end
|
55
|
+
end
|
55
56
|
|
57
|
+
class CbHasOneParent
|
58
|
+
include Mongoid::Document
|
56
59
|
include CallbackTracking
|
60
|
+
include RootInsertable
|
61
|
+
|
62
|
+
has_one :child, autosave: true, class_name: "CbHasOneChild", inverse_of: :parent
|
57
63
|
end
|
58
64
|
|
59
65
|
class CbHasOneChild
|
60
66
|
include Mongoid::Document
|
67
|
+
include CallbackTracking
|
61
68
|
|
62
69
|
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
70
|
end
|
73
71
|
|
74
72
|
class CbHasManyParent
|
75
73
|
include Mongoid::Document
|
74
|
+
include CallbackTracking
|
75
|
+
include RootInsertable
|
76
76
|
|
77
77
|
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
78
|
end
|
93
79
|
|
94
80
|
class CbHasManyChild
|
95
81
|
include Mongoid::Document
|
82
|
+
include CallbackTracking
|
96
83
|
|
97
84
|
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
85
|
end
|
108
86
|
|
109
87
|
class CbEmbedsOneParent
|
110
88
|
include Mongoid::Document
|
89
|
+
include CallbackTracking
|
90
|
+
include RootInsertable
|
111
91
|
|
112
92
|
field :name
|
113
93
|
|
114
94
|
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
95
|
end
|
130
96
|
|
131
97
|
class CbEmbedsOneChild
|
132
98
|
include Mongoid::Document
|
99
|
+
include CallbackTracking
|
133
100
|
|
134
101
|
field :age
|
135
102
|
|
136
103
|
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
104
|
end
|
147
105
|
|
148
106
|
class CbEmbedsManyParent
|
149
107
|
include Mongoid::Document
|
108
|
+
include CallbackTracking
|
109
|
+
include RootInsertable
|
150
110
|
|
151
111
|
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
112
|
end
|
167
113
|
|
168
114
|
class CbEmbedsManyChild
|
169
115
|
include Mongoid::Document
|
116
|
+
include CallbackTracking
|
170
117
|
|
171
118
|
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
119
|
end
|
182
120
|
|
183
121
|
class CbParent
|
184
122
|
include Mongoid::Document
|
185
|
-
|
186
|
-
def initialize(callback_registry)
|
187
|
-
@callback_registry = callback_registry
|
188
|
-
super()
|
189
|
-
end
|
190
|
-
|
191
|
-
attr_accessor :callback_registry
|
123
|
+
include CallbackTracking
|
192
124
|
|
193
125
|
embeds_many :cb_children
|
194
126
|
embeds_many :cb_cascaded_children, cascade_callbacks: true
|
195
|
-
|
196
|
-
include CallbackTracking
|
127
|
+
embeds_many :cb_cascaded_nodes, cascade_callbacks: true, as: :parent
|
197
128
|
end
|
198
129
|
|
199
130
|
class CbChild
|
200
131
|
include Mongoid::Document
|
132
|
+
include CallbackTracking
|
201
133
|
|
202
134
|
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
135
|
end
|
213
136
|
|
214
137
|
class CbCascadedChild
|
215
138
|
include Mongoid::Document
|
139
|
+
include CallbackTracking
|
216
140
|
|
217
141
|
embedded_in :cb_parent
|
218
142
|
|
219
|
-
|
220
|
-
@callback_registry = callback_registry
|
221
|
-
super(options)
|
222
|
-
end
|
143
|
+
before_save :test_mongoid_state
|
223
144
|
|
224
|
-
|
145
|
+
private
|
146
|
+
|
147
|
+
# Helps test that cascading child callbacks have access to the Mongoid
|
148
|
+
# state objects; if the implementation uses fiber-local (instead of truly
|
149
|
+
# thread-local) variables, the related tests will fail because the
|
150
|
+
# cascading child callbacks use fibers to linearize the recursion.
|
151
|
+
def test_mongoid_state
|
152
|
+
Mongoid::Threaded.stack('interceptable').push(self)
|
153
|
+
end
|
154
|
+
end
|
225
155
|
|
156
|
+
class CbCascadedNode
|
157
|
+
include Mongoid::Document
|
226
158
|
include CallbackTracking
|
159
|
+
|
160
|
+
embedded_in :parent, polymorphic: true
|
161
|
+
|
162
|
+
embeds_many :cb_cascaded_nodes, cascade_callbacks: true, as: :parent
|
227
163
|
end
|
228
164
|
end
|
229
165
|
|
@@ -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
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.1.
|
4
|
+
version: 8.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- The MongoDB Ruby Team
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-02-24 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: activemodel
|
@@ -1159,7 +1159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1159
1159
|
- !ruby/object:Gem::Version
|
1160
1160
|
version: 1.3.6
|
1161
1161
|
requirements: []
|
1162
|
-
rubygems_version: 3.6.
|
1162
|
+
rubygems_version: 3.6.5
|
1163
1163
|
specification_version: 4
|
1164
1164
|
summary: Elegant Persistence in Ruby for MongoDB.
|
1165
1165
|
test_files:
|