mongoid 8.0.6 → 8.0.8
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
- checksums.yaml.gz.sig +0 -0
- data/lib/mongoid/atomic.rb +9 -7
- data/lib/mongoid/config.rb +13 -0
- data/lib/mongoid/contextual/mongo.rb +24 -1
- data/lib/mongoid/deprecable.rb +3 -2
- data/lib/mongoid/deprecation.rb +3 -3
- data/lib/mongoid/extensions/hash.rb +19 -1
- data/lib/mongoid/interceptable.rb +122 -13
- data/lib/mongoid/validatable/associated.rb +96 -18
- 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_spec.rb +20 -0
- data/spec/mongoid/config_spec.rb +2 -2
- data/spec/mongoid/contextual/mongo_spec.rb +51 -6
- data/spec/mongoid/copyable_spec.rb +1 -1
- data/spec/mongoid/interceptable_spec.rb +362 -161
- data/spec/mongoid/validatable/associated_spec.rb +13 -30
- data/spec/shared/lib/mrss/docker_runner.rb +7 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +2 -2
- data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
- data/spec/shared/lib/mrss/utils.rb +28 -6
- data/spec/shared/share/Dockerfile.erb +36 -40
- data/spec/shared/shlib/server.sh +28 -4
- data/spec/shared/shlib/set_env.sh +4 -4
- data/spec/support/models/name.rb +10 -0
- data.tar.gz.sig +0 -0
- metadata +15 -15
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d604924530b809dbef3eef08d7e3c52b14e815d674821789a98c590f704b149
|
4
|
+
data.tar.gz: bfefc068fa68ed135560cff738dd7641f7df3780d01600a9f936752d5c760b8c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50280304426a7dc55cb2e86d2ce69d295f5b51df6f714dee96e4a5c0b8da00c1ca09ad516d300da6755cf5160699a982868bb46c1afd2da812f952ca8c18e240
|
7
|
+
data.tar.gz: 0fccee8bb9add55b0dfaa6454a33c89fe40553ce1a3fe9bef8be36fe4c92a884970d2e2b2a44c32761a198e750351276ef38f27a5e95f7fe11be02686425568b
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/mongoid/atomic.rb
CHANGED
@@ -178,13 +178,15 @@ module Mongoid
|
|
178
178
|
#
|
179
179
|
# @return [ Object ] The associated path.
|
180
180
|
def atomic_paths
|
181
|
-
@atomic_paths
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
181
|
+
return @atomic_paths if @atomic_paths
|
182
|
+
|
183
|
+
paths = if _association
|
184
|
+
_association.path(self)
|
185
|
+
else
|
186
|
+
Atomic::Paths::Root.new(self)
|
187
|
+
end
|
188
|
+
|
189
|
+
paths.tap { @atomic_paths = paths unless new_record? }
|
188
190
|
end
|
189
191
|
|
190
192
|
# Get all the attributes that need to be pulled.
|
data/lib/mongoid/config.rb
CHANGED
@@ -142,6 +142,19 @@ module Mongoid
|
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
145
|
+
# When this flag is true, callbacks for embedded documents will not be
|
146
|
+
# called. This is the default in 8.x, but will be changed to false in 9.0.
|
147
|
+
#
|
148
|
+
# Setting this flag to true (as it is in 8.x) may lead to stack
|
149
|
+
# overflow errors if there are more than cicrca 1000 embedded
|
150
|
+
# documents in the root document's dependencies graph.
|
151
|
+
#
|
152
|
+
# It is strongly recommended to set this flag to false in 8.x, if you
|
153
|
+
# are not using around callbacks for embedded documents.
|
154
|
+
#
|
155
|
+
# See https://jira.mongodb.org/browse/MONGOID-5658 for more details.
|
156
|
+
option :around_callbacks_for_embeds, default: true
|
157
|
+
|
145
158
|
# Has Mongoid been configured? This is checking that at least a valid
|
146
159
|
# client config exists.
|
147
160
|
#
|
@@ -56,7 +56,12 @@ module Mongoid
|
|
56
56
|
# @return [ Integer ] The number of matches.
|
57
57
|
def count(options = {}, &block)
|
58
58
|
return super(&block) if block_given?
|
59
|
-
|
59
|
+
|
60
|
+
if valid_for_count_documents?
|
61
|
+
view.count_documents(options)
|
62
|
+
else
|
63
|
+
view.count(options)
|
64
|
+
end
|
60
65
|
end
|
61
66
|
|
62
67
|
# Get the estimated number of documents matching the query.
|
@@ -813,6 +818,24 @@ module Mongoid
|
|
813
818
|
docs = eager_load(docs)
|
814
819
|
limit ? docs : docs.first
|
815
820
|
end
|
821
|
+
|
822
|
+
# Queries whether the current context is valid for use with
|
823
|
+
# the #count_documents? predicate. A context is valid if it
|
824
|
+
# does not include a `$where` operator.
|
825
|
+
#
|
826
|
+
# @return [ true | false ] whether or not the current context
|
827
|
+
# excludes a `$where` operator.
|
828
|
+
def valid_for_count_documents?(hash = view.filter)
|
829
|
+
# Note that `view.filter` is a BSON::Document, and all keys in a
|
830
|
+
# BSON::Document are strings; we don't need to worry about symbol
|
831
|
+
# representations of `$where`.
|
832
|
+
hash.keys.each do |key|
|
833
|
+
return false if key == '$where'
|
834
|
+
return false if hash[key].is_a?(Hash) && !valid_for_count_documents?(hash[key])
|
835
|
+
end
|
836
|
+
|
837
|
+
true
|
838
|
+
end
|
816
839
|
end
|
817
840
|
end
|
818
841
|
end
|
data/lib/mongoid/deprecable.rb
CHANGED
@@ -24,10 +24,11 @@ module Mongoid
|
|
24
24
|
# #=> Mongoid.logger.warn("meow is deprecated and will be removed from Mongoid 8.0 (eat :catnip instead)")
|
25
25
|
#
|
26
26
|
# @param [ Module ] target_module The parent which contains the method.
|
27
|
-
# @param [ Symbol | Hash<Symbol, [ Symbol | String ]> ] method_descriptors
|
27
|
+
# @param [ [ Symbol | Hash<Symbol, [ Symbol | String ]> ]... ] *method_descriptors
|
28
28
|
# The methods to deprecate, with optional replacement instructions.
|
29
29
|
def deprecate(target_module, *method_descriptors)
|
30
|
-
Mongoid::Deprecation.
|
30
|
+
@_deprecator ||= Mongoid::Deprecation.new
|
31
|
+
@_deprecator.deprecate_methods(target_module, *method_descriptors)
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
data/lib/mongoid/deprecation.rb
CHANGED
@@ -15,10 +15,10 @@ module Mongoid
|
|
15
15
|
#
|
16
16
|
# @return Array<Proc> The deprecation behavior.
|
17
17
|
def behavior
|
18
|
-
@behavior ||= Array(->(
|
18
|
+
@behavior ||= Array(->(*args) {
|
19
19
|
logger = Mongoid.logger
|
20
|
-
logger.warn(
|
21
|
-
logger.debug(
|
20
|
+
logger.warn(args[0])
|
21
|
+
logger.debug(args[1].join("\n ")) if debug
|
22
22
|
})
|
23
23
|
end
|
24
24
|
end
|
@@ -43,7 +43,7 @@ module Mongoid
|
|
43
43
|
real_key = klass.database_field_name(key2)
|
44
44
|
|
45
45
|
value.delete(key2) if real_key != key2
|
46
|
-
value[real_key] = (key
|
46
|
+
value[real_key] = value_for(key, klass, real_key, value2)
|
47
47
|
end
|
48
48
|
consolidated[key] ||= {}
|
49
49
|
consolidated[key].update(value)
|
@@ -185,6 +185,24 @@ module Mongoid
|
|
185
185
|
|
186
186
|
private
|
187
187
|
|
188
|
+
# Get the value for the provided operator, klass, key and value.
|
189
|
+
#
|
190
|
+
# This is necessary for special cases like $rename, $addToSet and $push.
|
191
|
+
#
|
192
|
+
# @param [ String ] operator The operator.
|
193
|
+
# @param [ Class ] klass The model class.
|
194
|
+
# @param [ String | Symbol ] key The field key.
|
195
|
+
# @param [ Object ] value The original value.
|
196
|
+
#
|
197
|
+
# @return [ Object ] Value prepared for the provided operator.
|
198
|
+
def value_for(operator, klass, key, value)
|
199
|
+
case operator
|
200
|
+
when "$rename" then value.to_s
|
201
|
+
when "$addToSet", "$push" then value.mongoize
|
202
|
+
else mongoize_for(operator, klass, operator, value)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
188
206
|
# Mongoize for the klass, key and value.
|
189
207
|
#
|
190
208
|
# @api private
|
@@ -79,7 +79,7 @@ module Mongoid
|
|
79
79
|
# @example Run only the after save callbacks.
|
80
80
|
# model.run_after_callbacks(:save)
|
81
81
|
#
|
82
|
-
# @param [
|
82
|
+
# @param [ Symbol... ] *kinds The events that are occurring.
|
83
83
|
#
|
84
84
|
# @return [ Object ] The result of the chain executing.
|
85
85
|
def run_after_callbacks(*kinds)
|
@@ -96,7 +96,7 @@ module Mongoid
|
|
96
96
|
# @example Run only the before save callbacks.
|
97
97
|
# model.run_before_callbacks(:save, :create)
|
98
98
|
#
|
99
|
-
# @param [
|
99
|
+
# @param [ Symbol... ] *kinds The events that are occurring.
|
100
100
|
#
|
101
101
|
# @return [ Object ] The result of the chain executing.
|
102
102
|
def run_before_callbacks(*kinds)
|
@@ -134,36 +134,126 @@ module Mongoid
|
|
134
134
|
# Run the callbacks for embedded documents.
|
135
135
|
#
|
136
136
|
# @param [ Symbol ] kind The type of callback to execute.
|
137
|
-
# @param [ Array<Document> ] children Children to
|
137
|
+
# @param [ Array<Document> ] children Children to execute callbacks on. If
|
138
138
|
# nil, callbacks will be executed on all cascadable children of
|
139
139
|
# the document.
|
140
140
|
#
|
141
141
|
# @api private
|
142
142
|
def _mongoid_run_child_callbacks(kind, children: nil, &block)
|
143
|
+
if Mongoid::Config.around_callbacks_for_embeds
|
144
|
+
_mongoid_run_child_callbacks_with_around(kind, children: children, &block)
|
145
|
+
else
|
146
|
+
_mongoid_run_child_callbacks_without_around(kind, children: children, &block)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Execute the callbacks of given kind for embedded documents including
|
151
|
+
# around callbacks.
|
152
|
+
#
|
153
|
+
# @note This method is prone to stack overflow errors if the document
|
154
|
+
# has a large number of embedded documents. It is recommended to avoid
|
155
|
+
# using around callbacks for embedded documents until a proper solution
|
156
|
+
# is implemented.
|
157
|
+
#
|
158
|
+
# @param [ Symbol ] kind The type of callback to execute.
|
159
|
+
# @param [ Array<Document> ] children Children to execute callbacks on. If
|
160
|
+
# nil, callbacks will be executed on all cascadable children of
|
161
|
+
# the document.
|
162
|
+
#
|
163
|
+
# @api private
|
164
|
+
def _mongoid_run_child_callbacks_with_around(kind, children: nil, &block)
|
143
165
|
child, *tail = (children || cascadable_children(kind))
|
144
166
|
if child.nil?
|
145
|
-
|
167
|
+
block&.call
|
146
168
|
elsif tail.empty?
|
147
|
-
|
169
|
+
child.run_callbacks(child_callback_type(kind, child), &block)
|
148
170
|
else
|
149
|
-
|
150
|
-
|
171
|
+
child.run_callbacks(child_callback_type(kind, child)) do
|
172
|
+
_mongoid_run_child_callbacks_with_around(kind, children: tail, &block)
|
151
173
|
end
|
152
174
|
end
|
153
175
|
end
|
154
176
|
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
158
|
-
#
|
177
|
+
# Execute the callbacks of given kind for embedded documents without
|
178
|
+
# around callbacks.
|
179
|
+
#
|
180
|
+
# @param [ Symbol ] kind The type of callback to execute.
|
181
|
+
# @param [ Array<Document> ] children Children to execute callbacks on. If
|
182
|
+
# nil, callbacks will be executed on all cascadable children of
|
183
|
+
# the document.
|
184
|
+
#
|
185
|
+
# @api private
|
186
|
+
def _mongoid_run_child_callbacks_without_around(kind, children: nil, &block)
|
187
|
+
children = (children || cascadable_children(kind))
|
188
|
+
callback_list = _mongoid_run_child_before_callbacks(kind, children: children)
|
189
|
+
return false if callback_list == false
|
190
|
+
value = block&.call
|
191
|
+
callback_list.each do |_next_sequence, env|
|
192
|
+
env.value &&= value
|
193
|
+
end
|
194
|
+
return false if _mongoid_run_child_after_callbacks(callback_list: callback_list) == false
|
195
|
+
|
196
|
+
value
|
197
|
+
end
|
198
|
+
|
199
|
+
# Execute the before callbacks of given kind for embedded documents.
|
200
|
+
#
|
201
|
+
# @param [ Symbol ] kind The type of callback to execute.
|
202
|
+
# @param [ Array<Document> ] children Children to execute callbacks on.
|
203
|
+
# @param [ Array<ActiveSupport::Callbacks::CallbackSequence, ActiveSupport::Callbacks::Filters::Environment> ] callback_list List of
|
204
|
+
# pairs of callback sequence and environment. This list will be later used
|
205
|
+
# to execute after callbacks in reverse order.
|
159
206
|
#
|
160
|
-
# @
|
207
|
+
# @api private
|
208
|
+
def _mongoid_run_child_before_callbacks(kind, children: [], callback_list: [])
|
209
|
+
children.each do |child|
|
210
|
+
chain = child.__callbacks[child_callback_type(kind, child)]
|
211
|
+
env = ActiveSupport::Callbacks::Filters::Environment.new(child, false, nil)
|
212
|
+
next_sequence = compile_callbacks(chain)
|
213
|
+
unless next_sequence.final?
|
214
|
+
Mongoid.logger.warn("Around callbacks are disabled for embedded documents. Skipping around callbacks for #{child.class.name}.")
|
215
|
+
Mongoid.logger.warn("To enable around callbacks for embedded documents, set Mongoid::Config.around_callbacks_for_embeds to true.")
|
216
|
+
end
|
217
|
+
next_sequence.invoke_before(env)
|
218
|
+
return false if env.halted
|
219
|
+
env.value = !env.halted
|
220
|
+
callback_list << [next_sequence, env]
|
221
|
+
if (grandchildren = child.send(:cascadable_children, kind))
|
222
|
+
_mongoid_run_child_before_callbacks(kind, children: grandchildren, callback_list: callback_list)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
callback_list
|
226
|
+
end
|
227
|
+
|
228
|
+
# Execute the after callbacks.
|
229
|
+
#
|
230
|
+
# @param [ Array<ActiveSupport::Callbacks::CallbackSequence, ActiveSupport::Callbacks::Filters::Environment> ] callback_list List of
|
231
|
+
# pairs of callback sequence and environment.
|
232
|
+
def _mongoid_run_child_after_callbacks(callback_list: [])
|
233
|
+
callback_list.reverse_each do |next_sequence, env|
|
234
|
+
next_sequence.invoke_after(env)
|
235
|
+
return false if env.halted
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Returns the stored callbacks to be executed later.
|
240
|
+
#
|
241
|
+
# @return [ Array<Symbol> ] Method symbols of the stored pending callbacks.
|
161
242
|
#
|
162
243
|
# @api private
|
163
244
|
def pending_callbacks
|
164
245
|
@pending_callbacks ||= [].to_set
|
165
246
|
end
|
166
247
|
|
248
|
+
# Stores callbacks to be executed later. A good use case for
|
249
|
+
# this is delaying the after_find and after_initialize callbacks until the
|
250
|
+
# associations are set on the document. This can also be used to delay
|
251
|
+
# applying the defaults on a document.
|
252
|
+
#
|
253
|
+
# @param [ Array<Symbol> ] value Method symbols of the pending callbacks to store.
|
254
|
+
#
|
255
|
+
# @return [ Array<Symbol> ] Method symbols of the stored pending callbacks.
|
256
|
+
#
|
167
257
|
# @api private
|
168
258
|
def pending_callbacks=(value)
|
169
259
|
@pending_callbacks = value
|
@@ -298,7 +388,7 @@ module Mongoid
|
|
298
388
|
end
|
299
389
|
self.class.send :define_method, name do
|
300
390
|
env = ActiveSupport::Callbacks::Filters::Environment.new(self, false, nil)
|
301
|
-
sequence = chain
|
391
|
+
sequence = compile_callbacks(chain)
|
302
392
|
sequence.invoke_before(env)
|
303
393
|
env.value = !env.halted
|
304
394
|
sequence.invoke_after(env)
|
@@ -308,5 +398,24 @@ module Mongoid
|
|
308
398
|
end
|
309
399
|
send(name)
|
310
400
|
end
|
401
|
+
|
402
|
+
# Compile the callback chain.
|
403
|
+
#
|
404
|
+
# This method hides the differences between ActiveSupport implementations
|
405
|
+
# before and after 7.1.
|
406
|
+
#
|
407
|
+
# @param [ ActiveSupport::Callbacks::CallbackChain ] chain The callback chain.
|
408
|
+
# @param [ Symbol | nil ] type The type of callback chain to compile.
|
409
|
+
#
|
410
|
+
# @return [ ActiveSupport::Callbacks::CallbackSequence ] The compiled callback sequence.
|
411
|
+
def compile_callbacks(chain, type = nil)
|
412
|
+
if chain.method(:compile).arity == 0
|
413
|
+
# ActiveSupport < 7.1
|
414
|
+
chain.compile
|
415
|
+
else
|
416
|
+
# ActiveSupport >= 7.1
|
417
|
+
chain.compile(type)
|
418
|
+
end
|
419
|
+
end
|
311
420
|
end
|
312
421
|
end
|
@@ -15,32 +15,110 @@ module Mongoid
|
|
15
15
|
#
|
16
16
|
# validates_associated :name, :addresses
|
17
17
|
# end
|
18
|
-
class AssociatedValidator < ActiveModel::
|
18
|
+
class AssociatedValidator < ActiveModel::Validator
|
19
|
+
# Required by `validates_with` so that the validator
|
20
|
+
# gets added to the correct attributes.
|
21
|
+
def attributes
|
22
|
+
options[:attributes]
|
23
|
+
end
|
19
24
|
|
20
|
-
#
|
21
|
-
# valid.
|
22
|
-
# the
|
25
|
+
# Checks that the named associations of the given record
|
26
|
+
# (`attributes`) are valid. This does NOT load the associations
|
27
|
+
# from the database, and will only validate records that are dirty
|
28
|
+
# or unpersisted.
|
23
29
|
#
|
24
|
-
#
|
25
|
-
#
|
30
|
+
# If anything is not valid, appropriate errors will be added to
|
31
|
+
# the `document` parameter.
|
32
|
+
#
|
33
|
+
# @param [ Mongoid::Document ] document the document with the
|
34
|
+
# associations to validate.
|
35
|
+
def validate(document)
|
36
|
+
options[:attributes].each do |attr_name|
|
37
|
+
validate_association(document, attr_name)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Validates that the given association provided is either nil,
|
44
|
+
# persisted and unchanged, or invalid. Otherwise, the appropriate errors
|
45
|
+
# will be added to the parent document.
|
26
46
|
#
|
27
47
|
# @param [ Document ] document The document to validate.
|
28
48
|
# @param [ Symbol ] attribute The association to validate.
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
49
|
+
def validate_association(document, attribute)
|
50
|
+
# grab the proxy from the instance variable directly; we don't want
|
51
|
+
# any loading logic to run; we just want to see if it's already
|
52
|
+
# been loaded.
|
53
|
+
proxy = document.ivar(attribute)
|
54
|
+
return unless proxy
|
55
|
+
|
56
|
+
# if the variable exists, now we see if it is a proxy, or an actual
|
57
|
+
# document. It might be a literal document instead of a proxy if this
|
58
|
+
# document was created with a Document instance as a provided attribute,
|
59
|
+
# e.g. "Post.new(message: Message.new)".
|
60
|
+
target = proxy.respond_to?(:_target) ? proxy._target : proxy
|
61
|
+
|
62
|
+
# Now, fetch the list of documents from the target. Target may be a
|
63
|
+
# single value, or a list of values, and in the case of HasMany,
|
64
|
+
# might be a rather complex collection. We need to do this without
|
65
|
+
# triggering a load, so it's a bit of a delicate dance.
|
66
|
+
list = get_target_documents(target)
|
67
|
+
|
68
|
+
valid = document.validating do
|
69
|
+
# Now, treating the target as an array, look at each element
|
70
|
+
# and see if it is valid, but only if it has already been
|
71
|
+
# persisted, or changed, and hasn't been flagged for destroy.
|
72
|
+
list.all? do |value|
|
73
|
+
if value && !value.flagged_for_destroy? && (!value.persisted? || value.changed?)
|
74
|
+
value.validated? ? true : value.valid?
|
36
75
|
else
|
37
|
-
|
76
|
+
true
|
38
77
|
end
|
39
|
-
end
|
40
|
-
|
41
|
-
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
document.errors.add(attribute, :invalid) unless valid
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Examine the given target object and return an array of
|
87
|
+
# documents (possibly empty) that the target represents.
|
88
|
+
#
|
89
|
+
# @param [ Array | Mongoid::Document | Mongoid::Association::Proxy | HasMany::Enumerable ] target
|
90
|
+
# the target object to examine.
|
91
|
+
#
|
92
|
+
# @return [ Array<Mongoid::Document> ] the list of documents
|
93
|
+
def get_target_documents(target)
|
94
|
+
if target.respond_to?(:_loaded?)
|
95
|
+
get_target_documents_for_has_many(target)
|
96
|
+
else
|
97
|
+
get_target_documents_for_other(target)
|
42
98
|
end
|
43
|
-
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns the list of all currently in-memory values held by
|
102
|
+
# the target. The target will not be loaded.
|
103
|
+
#
|
104
|
+
# @param [ HasMany::Enumerable ] target the target that will
|
105
|
+
# be examined for in-memory documents.
|
106
|
+
#
|
107
|
+
# @return [ Array<Mongoid::Document> ] the in-memory documents
|
108
|
+
# held by the target.
|
109
|
+
def get_target_documents_for_has_many(target)
|
110
|
+
[ *target._loaded.values, *target._added.values ]
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns the target as an array. If the target represents a single
|
114
|
+
# value, it is wrapped in an array.
|
115
|
+
#
|
116
|
+
# @param [ Array | Mongoid::Document | Mongoid::Association::Proxy ] target
|
117
|
+
# the target to return.
|
118
|
+
#
|
119
|
+
# @return [ Array<Mongoid::Document> ] the target, as an array.
|
120
|
+
def get_target_documents_for_other(target)
|
121
|
+
Array.wrap(target)
|
44
122
|
end
|
45
123
|
end
|
46
124
|
end
|
data/lib/mongoid/validatable.rb
CHANGED
@@ -37,6 +37,14 @@ module Mongoid
|
|
37
37
|
Threaded.exit_validate(self)
|
38
38
|
end
|
39
39
|
|
40
|
+
# Perform a validation within the associated block.
|
41
|
+
def validating
|
42
|
+
begin_validate
|
43
|
+
yield
|
44
|
+
ensure
|
45
|
+
exit_validate
|
46
|
+
end
|
47
|
+
|
40
48
|
# Given the provided options, are we performing validations?
|
41
49
|
#
|
42
50
|
# @example Are we performing validations?
|
data/lib/mongoid/version.rb
CHANGED
@@ -2,6 +2,28 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
+
module HabtmSpec
|
6
|
+
class Page
|
7
|
+
include Mongoid::Document
|
8
|
+
embeds_many :blocks, class_name: 'HabtmSpec::Block'
|
9
|
+
end
|
10
|
+
|
11
|
+
class Block
|
12
|
+
include Mongoid::Document
|
13
|
+
embedded_in :page, class_name: 'HabtmSpec::Page'
|
14
|
+
end
|
15
|
+
|
16
|
+
class ImageBlock < Block
|
17
|
+
has_and_belongs_to_many :attachments, inverse_of: nil, class_name: 'HabtmSpec::Attachment'
|
18
|
+
accepts_nested_attributes_for :attachments
|
19
|
+
end
|
20
|
+
|
21
|
+
class Attachment
|
22
|
+
include Mongoid::Document
|
23
|
+
field :file, type: String
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
5
27
|
describe 'has_and_belongs_to_many associations' do
|
6
28
|
|
7
29
|
context 'when an anonymous class defines a has_and_belongs_to_many association' do
|
@@ -18,4 +40,22 @@ describe 'has_and_belongs_to_many associations' do
|
|
18
40
|
expect(klass.new.movies.build).to be_a Movie
|
19
41
|
end
|
20
42
|
end
|
43
|
+
|
44
|
+
context 'when an embedded has habtm relation' do
|
45
|
+
let(:attachment) { HabtmSpec::Attachment.create!(file: 'foo.jpg') }
|
46
|
+
|
47
|
+
let(:page) { HabtmSpec::Page.create! }
|
48
|
+
|
49
|
+
let(:image_block) do
|
50
|
+
image_block = page.blocks.build({
|
51
|
+
_type: 'HabtmSpec::ImageBlock',
|
52
|
+
attachment_ids: [ attachment.id.to_s ],
|
53
|
+
attachments_attributes: { '1234' => { file: 'bar.jpg', id: attachment.id.to_s } }
|
54
|
+
})
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'does not raise on save' do
|
58
|
+
expect { image_block.save! }.not_to raise_error
|
59
|
+
end
|
60
|
+
end
|
21
61
|
end
|
@@ -447,4 +447,24 @@ describe 'callbacks integration tests' do
|
|
447
447
|
expect(saved_person.previously_persisted_value).to be_truthy
|
448
448
|
end
|
449
449
|
end
|
450
|
+
|
451
|
+
context 'cascade callbacks' do
|
452
|
+
ruby_version_gte '3.0'
|
453
|
+
config_override :around_callbacks_for_embeds, false
|
454
|
+
|
455
|
+
let(:book) do
|
456
|
+
Book.new
|
457
|
+
end
|
458
|
+
|
459
|
+
before do
|
460
|
+
1500.times do
|
461
|
+
book.pages.build
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
# https://jira.mongodb.org/browse/MONGOID-5658
|
466
|
+
it 'does not raise SystemStackError' do
|
467
|
+
expect { book.save! }.not_to raise_error(SystemStackError)
|
468
|
+
end
|
469
|
+
end
|
450
470
|
end
|
data/spec/mongoid/config_spec.rb
CHANGED
@@ -608,7 +608,7 @@ describe Mongoid::Config do
|
|
608
608
|
|
609
609
|
it 'passes uuid to driver' do
|
610
610
|
Mongo::Client.should receive(:new).with(SpecConfig.instance.addresses,
|
611
|
-
auto_encryption_options: {
|
611
|
+
{ auto_encryption_options: {
|
612
612
|
'key_vault_namespace' => 'admin.datakeys',
|
613
613
|
'kms_providers' => {'local' => {'key' => 'z7iYiYKLuYymEWtk4kfny1ESBwwFdA58qMqff96A8ghiOcIK75lJGPUIocku8LOFjQuEgeIP4xlln3s7r93FV9J5sAE7zg8U'}},
|
614
614
|
'schema_map' => {'blog_development.comments' => {
|
@@ -625,7 +625,7 @@ describe Mongoid::Config do
|
|
625
625
|
platform: "mongoid-#{Mongoid::VERSION}",
|
626
626
|
wrapping_libraries: [
|
627
627
|
{'name' => 'Mongoid', 'version' => Mongoid::VERSION},
|
628
|
-
],
|
628
|
+
]},
|
629
629
|
)
|
630
630
|
|
631
631
|
client
|
@@ -158,6 +158,16 @@ describe Mongoid::Contextual::Mongo do
|
|
158
158
|
end
|
159
159
|
end
|
160
160
|
end
|
161
|
+
|
162
|
+
context 'when for_js is present' do
|
163
|
+
let(:context) do
|
164
|
+
Band.for_js('this.name == "Depeche Mode"')
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'counts the expected records' do
|
168
|
+
expect(context.count).to eq(1)
|
169
|
+
end
|
170
|
+
end
|
161
171
|
end
|
162
172
|
|
163
173
|
describe "#estimated_count" do
|
@@ -3563,16 +3573,51 @@ describe Mongoid::Contextual::Mongo do
|
|
3563
3573
|
|
3564
3574
|
context "when the attributes are in the correct type" do
|
3565
3575
|
|
3566
|
-
|
3567
|
-
|
3576
|
+
context "when operation is $set" do
|
3577
|
+
|
3578
|
+
before do
|
3579
|
+
context.update_all("$set" => { name: "Smiths" })
|
3580
|
+
end
|
3581
|
+
|
3582
|
+
it "updates the first matching document" do
|
3583
|
+
expect(depeche_mode.reload.name).to eq("Smiths")
|
3584
|
+
end
|
3585
|
+
|
3586
|
+
it "updates the last matching document" do
|
3587
|
+
expect(new_order.reload.name).to eq("Smiths")
|
3588
|
+
end
|
3568
3589
|
end
|
3569
3590
|
|
3570
|
-
|
3571
|
-
|
3591
|
+
context "when operation is $push" do
|
3592
|
+
|
3593
|
+
before do
|
3594
|
+
depeche_mode.update_attribute(:genres, ["electronic"])
|
3595
|
+
new_order.update_attribute(:genres, ["electronic"])
|
3596
|
+
context.update_all("$push" => { genres: "pop" })
|
3597
|
+
end
|
3598
|
+
|
3599
|
+
it "updates the first matching document" do
|
3600
|
+
expect(depeche_mode.reload.genres).to eq(["electronic", "pop"])
|
3601
|
+
end
|
3602
|
+
|
3603
|
+
it "updates the last matching document" do
|
3604
|
+
expect(new_order.reload.genres).to eq(["electronic", "pop"])
|
3605
|
+
end
|
3572
3606
|
end
|
3573
3607
|
|
3574
|
-
|
3575
|
-
|
3608
|
+
context "when operation is $addToSet" do
|
3609
|
+
|
3610
|
+
before do
|
3611
|
+
context.update_all("$addToSet" => { genres: "electronic" })
|
3612
|
+
end
|
3613
|
+
|
3614
|
+
it "updates the first matching document" do
|
3615
|
+
expect(depeche_mode.reload.genres).to eq(["electronic"])
|
3616
|
+
end
|
3617
|
+
|
3618
|
+
it "updates the last matching document" do
|
3619
|
+
expect(new_order.reload.genres).to eq(["electronic"])
|
3620
|
+
end
|
3576
3621
|
end
|
3577
3622
|
end
|
3578
3623
|
|