mongoid 9.0.1 → 9.0.3
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/config/locales/en.yml +16 -0
- data/lib/mongoid/association/accessors.rb +7 -2
- data/lib/mongoid/association/nested/one.rb +14 -1
- data/lib/mongoid/association/referenced/belongs_to/binding.rb +7 -1
- data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
- data/lib/mongoid/association/referenced/belongs_to.rb +15 -0
- data/lib/mongoid/association/referenced/has_many.rb +9 -8
- data/lib/mongoid/association/referenced/has_one/buildable.rb +3 -8
- data/lib/mongoid/association/referenced/with_polymorphic_criteria.rb +41 -0
- data/lib/mongoid/attributes/nested.rb +2 -1
- data/lib/mongoid/clients/options.rb +14 -1
- data/lib/mongoid/clients/sessions.rb +13 -15
- data/lib/mongoid/composable.rb +2 -0
- data/lib/mongoid/document.rb +2 -0
- data/lib/mongoid/errors/unrecognized_model_alias.rb +53 -0
- data/lib/mongoid/errors/unrecognized_resolver.rb +27 -0
- data/lib/mongoid/errors/unregistered_class.rb +47 -0
- data/lib/mongoid/errors.rb +3 -0
- data/lib/mongoid/identifiable.rb +28 -0
- data/lib/mongoid/matcher.rb +15 -1
- data/lib/mongoid/model_resolver.rb +154 -0
- data/lib/mongoid/persistence_context.rb +15 -9
- data/lib/mongoid/railties/controller_runtime.rb +2 -2
- data/lib/mongoid/serializable.rb +7 -7
- data/lib/mongoid/threaded.rb +96 -28
- data/lib/mongoid/timestamps/timeless.rb +4 -1
- data/lib/mongoid/touchable.rb +1 -1
- data/lib/mongoid/traversable.rb +11 -2
- data/lib/mongoid/validatable/associated.rb +5 -2
- data/lib/mongoid/version.rb +1 -1
- data/spec/integration/active_job_spec.rb +24 -20
- data/spec/integration/app_spec.rb +9 -1
- data/spec/integration/associations/belongs_to_spec.rb +129 -0
- data/spec/integration/persistence/collection_options_spec.rb +36 -0
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +4 -0
- data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +5 -0
- data/spec/mongoid/association/referenced/belongs_to_spec.rb +58 -21
- data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +4 -0
- data/spec/mongoid/attributes/nested_spec.rb +1 -0
- data/spec/mongoid/clients/options_spec.rb +127 -2
- data/spec/mongoid/clients/transactions_spec.rb +2 -2
- data/spec/mongoid/interceptable_spec.rb +12 -0
- data/spec/mongoid/interceptable_spec_models.rb +12 -0
- data/spec/mongoid/model_resolver_spec.rb +167 -0
- data/spec/mongoid/monkey_patches_spec.rb +1 -1
- data/spec/mongoid/persistence_context_spec.rb +48 -4
- data/spec/mongoid/railties/bson_object_id_serializer_spec.rb +18 -12
- data/spec/mongoid/serializable_spec.rb +16 -9
- data/spec/mongoid/threaded_spec.rb +24 -5
- data/spec/mongoid/validatable/associated_spec.rb +14 -4
- data/spec/rails/controller_extension/controller_runtime_spec.rb +14 -14
- metadata +14 -4
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Mongoid
|
6
|
+
# The default class for resolving model classes based on discriminant keys.
|
7
|
+
# Given a key, it will return the corresponding model class, if any. By
|
8
|
+
# default, it looks for classes with names that match the given keys, but
|
9
|
+
# additional mappings may be provided.
|
10
|
+
#
|
11
|
+
# It is also possible to instantiate multiple resolvers---and even implement
|
12
|
+
# your own---so that different sets of classes can use independent resolution
|
13
|
+
# mechanics.
|
14
|
+
class ModelResolver
|
15
|
+
# The mutex instance used to make the `.instance` method thread-safe.
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
INSTANCE_MUTEX = Mutex.new
|
19
|
+
|
20
|
+
class << self
|
21
|
+
extend Forwardable
|
22
|
+
def_delegators :instance, :register
|
23
|
+
|
24
|
+
# Returns the default instance of the ModelResolver.
|
25
|
+
#
|
26
|
+
# @return [ Mongoid::ModelResolver ] the default ModelResolver instance.
|
27
|
+
def instance
|
28
|
+
@instance ||= INSTANCE_MUTEX.synchronize { @instance ||= new }
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the map of registered resolvers. The default resolver is not
|
32
|
+
# included here.
|
33
|
+
#
|
34
|
+
# @return [ Hash<Symbol => Mongoid::ModelResolver::Interface> ] the hash of
|
35
|
+
# resolver instances, mapped by symbol identifier.
|
36
|
+
def resolvers
|
37
|
+
@resolvers ||= {}
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the resolver instance that corresponds to the argument.
|
41
|
+
#
|
42
|
+
# @param [ nil | true | false Symbol | String | Mongoid::ModelResolver::Interface ] identifier_or_object
|
43
|
+
# When nil or false, returns nil. When true or :default, corresponds to the default resolver.
|
44
|
+
# When any other symbol or string, corresponds to the registered resolver with that identifier.
|
45
|
+
# Otherwise, it must be a resolver instance itself.
|
46
|
+
#
|
47
|
+
# @raise Mongoid::Errors::UnrecognizedResolver if the given identifier is a
|
48
|
+
# symbol or string and it does not match any registered resolver.
|
49
|
+
#
|
50
|
+
# @return [ Mongoid::ModelResolver::Interface ] the resolver instance corresponding to the
|
51
|
+
# given argument.
|
52
|
+
def resolver(identifier_or_object = :default)
|
53
|
+
case identifier_or_object
|
54
|
+
when nil, false then nil
|
55
|
+
when true, :default then instance
|
56
|
+
when String, Symbol
|
57
|
+
resolvers.fetch(identifier_or_object.to_sym) do |key|
|
58
|
+
raise Mongoid::Errors::UnrecognizedResolver, key
|
59
|
+
end
|
60
|
+
else identifier_or_object
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Register the given resolver under the given name.
|
65
|
+
#
|
66
|
+
# @param [ Mongoid::ModelResolver::Interface ] resolver the resolver to register.
|
67
|
+
# @param [ String | Symbol ] name the identifier to use to register the resolver.
|
68
|
+
def register_resolver(resolver, name)
|
69
|
+
resolvers[name.to_sym] = resolver
|
70
|
+
self
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Instantiates a new ModelResolver instance.
|
75
|
+
def initialize
|
76
|
+
@key_to_model = {}
|
77
|
+
@model_to_keys = {}
|
78
|
+
end
|
79
|
+
|
80
|
+
# Registers the given model class with the given keys. In addition to the given keys, the
|
81
|
+
# class name itself will be included as a key to identify the class. Keys are given in priority
|
82
|
+
# order, with highest priority keys first and lowest last. The class name, if not given explicitly,
|
83
|
+
# is always given lowest priority.
|
84
|
+
#
|
85
|
+
# If called more than once, newer keys have higher priority than older keys. All duplicate keys will
|
86
|
+
# be removed.
|
87
|
+
#
|
88
|
+
# @param [ Mongoid::Document ] klass the document class to register
|
89
|
+
# @param [ Array<String> ] *keys the list of keys to use as an alias (optional)
|
90
|
+
def register(klass, *keys)
|
91
|
+
default_key = klass.name
|
92
|
+
|
93
|
+
@model_to_keys[klass] = [ *keys, *@model_to_keys[klass], default_key ].uniq
|
94
|
+
@key_to_model[default_key] = klass
|
95
|
+
|
96
|
+
keys.each do |key|
|
97
|
+
@key_to_model[key] = klass
|
98
|
+
end
|
99
|
+
|
100
|
+
self
|
101
|
+
end
|
102
|
+
|
103
|
+
# The `Interface` concern represents the interface that custom resolvers
|
104
|
+
# must implement.
|
105
|
+
concerning :Interface do
|
106
|
+
# Returns the default (highest priority) key for the given record. This is typically
|
107
|
+
# the key that will be used when saving a new polymorphic association.
|
108
|
+
#
|
109
|
+
# @param [ Mongoid::Document ] record the record instance for which to query the default key.
|
110
|
+
#
|
111
|
+
# @raise Mongoid::Errors::UnregisteredClass if the record's class has not been registered with this resolver.
|
112
|
+
#
|
113
|
+
# @return [ String ] the default key for the record's class.
|
114
|
+
def default_key_for(record)
|
115
|
+
keys_for(record).first
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns the list of all keys for the given record's class, in priority order (with highest
|
119
|
+
# priority keys first).
|
120
|
+
#
|
121
|
+
# @param [ Mongoid::Document] record the record instance for which to query the registered keys.
|
122
|
+
#
|
123
|
+
# @raise Mongoid::Errors::UnregisteredClass if the record's class has not been registered with this resolver.
|
124
|
+
#
|
125
|
+
# @return [ Array<String> ] the list of keys that have been registered for the given class.
|
126
|
+
def keys_for(record)
|
127
|
+
@model_to_keys.fetch(record.class) do |klass|
|
128
|
+
# figure out which resolver this is
|
129
|
+
resolver = if self == Mongoid::ModelResolver.instance
|
130
|
+
:default
|
131
|
+
else
|
132
|
+
Mongoid::ModelResolver.resolvers.keys.detect { |k| Mongoid::ModelResolver.resolvers[k] == self }
|
133
|
+
end
|
134
|
+
resolver ||= self # if it hasn't been registered, we'll show it the best we can
|
135
|
+
raise Mongoid::Errors::UnregisteredClass.new(klass, resolver)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns the document class that has been registered by the given key.
|
140
|
+
#
|
141
|
+
# @param [ String ] key the key by which to query the corresponding class.
|
142
|
+
#
|
143
|
+
# @raise Mongoid::Errors::UnrecognizedModelAlias if the given key has not
|
144
|
+
# been registered with this resolver.
|
145
|
+
#
|
146
|
+
# @return [ Class ] the document class that has been registered with the given key.
|
147
|
+
def model_for(key)
|
148
|
+
@key_to_model.fetch(key) do
|
149
|
+
raise Mongoid::Errors::UnrecognizedModelAlias, key
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -25,7 +25,8 @@ module Mongoid
|
|
25
25
|
# @return [ Array<Symbol> ] The list of extra options besides client options
|
26
26
|
# that determine the persistence context.
|
27
27
|
EXTRA_OPTIONS = [ :client,
|
28
|
-
:collection
|
28
|
+
:collection,
|
29
|
+
:collection_options
|
29
30
|
].freeze
|
30
31
|
|
31
32
|
# The full list of valid persistence context options.
|
@@ -116,12 +117,15 @@ module Mongoid
|
|
116
117
|
def client
|
117
118
|
@client ||= begin
|
118
119
|
client = Clients.with_name(client_name)
|
120
|
+
options = client_options
|
121
|
+
|
119
122
|
if database_name_option
|
120
123
|
client = client.use(database_name)
|
124
|
+
options = options.except(:database, 'database')
|
121
125
|
end
|
122
|
-
|
123
|
-
|
124
|
-
|
126
|
+
|
127
|
+
client = client.with(options) unless options.empty?
|
128
|
+
|
125
129
|
client
|
126
130
|
end
|
127
131
|
end
|
@@ -281,6 +285,10 @@ module Mongoid
|
|
281
285
|
# @api private
|
282
286
|
PERSISTENCE_CONTEXT_KEY = :"[mongoid]:persistence_context"
|
283
287
|
|
288
|
+
def context_store
|
289
|
+
Threaded.get(PERSISTENCE_CONTEXT_KEY) { {} }
|
290
|
+
end
|
291
|
+
|
284
292
|
# Get the persistence context for a given object from the thread local
|
285
293
|
# storage.
|
286
294
|
#
|
@@ -291,8 +299,7 @@ module Mongoid
|
|
291
299
|
#
|
292
300
|
# @api private
|
293
301
|
def get_context(object)
|
294
|
-
|
295
|
-
Thread.current[PERSISTENCE_CONTEXT_KEY][object.object_id]
|
302
|
+
context_store[object.object_id]
|
296
303
|
end
|
297
304
|
|
298
305
|
# Store persistence context for a given object in the thread local
|
@@ -304,10 +311,9 @@ module Mongoid
|
|
304
311
|
# @api private
|
305
312
|
def store_context(object, context)
|
306
313
|
if context.nil?
|
307
|
-
|
314
|
+
context_store.delete(object.object_id)
|
308
315
|
else
|
309
|
-
|
310
|
-
Thread.current[PERSISTENCE_CONTEXT_KEY][object.object_id] = context
|
316
|
+
context_store[object.object_id] = context
|
311
317
|
end
|
312
318
|
end
|
313
319
|
end
|
@@ -78,7 +78,7 @@ module Mongoid
|
|
78
78
|
#
|
79
79
|
# @return [ Integer ] The runtime value.
|
80
80
|
def self.runtime
|
81
|
-
|
81
|
+
Threaded.get(VARIABLE_NAME) { 0 }
|
82
82
|
end
|
83
83
|
|
84
84
|
# Set the runtime value on the current thread.
|
@@ -87,7 +87,7 @@ module Mongoid
|
|
87
87
|
#
|
88
88
|
# @return [ Integer ] The runtime value.
|
89
89
|
def self.runtime= value
|
90
|
-
|
90
|
+
Threaded.set(VARIABLE_NAME, value)
|
91
91
|
end
|
92
92
|
|
93
93
|
# Reset the runtime value to zero the current thread.
|
data/lib/mongoid/serializable.rb
CHANGED
@@ -13,13 +13,13 @@ module Mongoid
|
|
13
13
|
included do
|
14
14
|
|
15
15
|
class << self
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
def include_root_in_json
|
17
|
+
@include_root_in_json.nil? ? ::Mongoid.include_root_in_json : @include_root_in_json
|
18
|
+
end
|
19
|
+
|
20
|
+
def include_root_in_json=(new_value)
|
21
|
+
@include_root_in_json = new_value
|
22
|
+
end
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
data/lib/mongoid/threaded.rb
CHANGED
@@ -18,6 +18,7 @@ module Mongoid
|
|
18
18
|
CURRENT_SCOPE_KEY = '[mongoid]:current-scope'
|
19
19
|
|
20
20
|
AUTOSAVES_KEY = '[mongoid]:autosaves'
|
21
|
+
|
21
22
|
VALIDATIONS_KEY = '[mongoid]:validations'
|
22
23
|
|
23
24
|
STACK_KEYS = Hash.new do |hash, key|
|
@@ -36,6 +37,75 @@ module Mongoid
|
|
36
37
|
|
37
38
|
extend self
|
38
39
|
|
40
|
+
# Queries the thread-local variable with the given name. If a block is
|
41
|
+
# given, and the variable does not already exist, the return value of the
|
42
|
+
# block will be set as the value of the variable before returning it.
|
43
|
+
#
|
44
|
+
# It is very important that applications (and espcially Mongoid)
|
45
|
+
# use this method instead of Thread#[], since Thread#[] is actually for
|
46
|
+
# fiber-local variables, and Mongoid uses Fibers as an implementation
|
47
|
+
# detail in some callbacks. Putting thread-local state in a fiber-local
|
48
|
+
# store will result in the state being invisible when relevant callbacks are
|
49
|
+
# run in a different fiber.
|
50
|
+
#
|
51
|
+
# Affected callbacks are cascading callbacks on embedded children.
|
52
|
+
#
|
53
|
+
# @param [ String | Symbol ] key the name of the variable to query
|
54
|
+
# @param [ Proc ] default an optional block that must return the default
|
55
|
+
# (initial) value of this variable.
|
56
|
+
#
|
57
|
+
# @return [ Object | nil ] the value of the queried variable, or nil if
|
58
|
+
# it is not set and no default was given.
|
59
|
+
def get(key, &default)
|
60
|
+
result = Thread.current.thread_variable_get(key)
|
61
|
+
|
62
|
+
if result.nil? && default
|
63
|
+
result = yield
|
64
|
+
set(key, result)
|
65
|
+
end
|
66
|
+
|
67
|
+
result
|
68
|
+
end
|
69
|
+
|
70
|
+
# Sets a thread-local variable with the given name to the given value.
|
71
|
+
# See #get for a discussion of why this method is necessary, and why
|
72
|
+
# Thread#[]= should be avoided in cascading callbacks on embedded children.
|
73
|
+
#
|
74
|
+
# @param [ String | Symbol ] key the name of the variable to set.
|
75
|
+
# @param [ Object | nil ] value the value of the variable to set (or `nil`
|
76
|
+
# if you wish to unset the variable)
|
77
|
+
def set(key, value)
|
78
|
+
Thread.current.thread_variable_set(key, value)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Removes the named variable from thread-local storage.
|
82
|
+
#
|
83
|
+
# @param [ String | Symbol ] key the name of the variable to remove.
|
84
|
+
def delete(key)
|
85
|
+
set(key, nil)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Queries the presence of a named variable in thread-local storage.
|
89
|
+
#
|
90
|
+
# @param [ String | Symbol ] key the name of the variable to query.
|
91
|
+
#
|
92
|
+
# @return [ true | false ] whether the given variable is present or not.
|
93
|
+
def has?(key)
|
94
|
+
# Here we have a classic example of JRuby not behaving like MRI. In
|
95
|
+
# MRI, if you set a thread variable to nil, it removes it from the list
|
96
|
+
# and subsequent calls to thread_variable?(key) will return false. Not
|
97
|
+
# so with JRuby. Once set, you cannot unset the thread variable.
|
98
|
+
#
|
99
|
+
# However, because setting a variable to nil is supposed to remove it,
|
100
|
+
# we can assume a nil-valued variable doesn't actually exist.
|
101
|
+
|
102
|
+
# So, instead of this:
|
103
|
+
# Thread.current.thread_variable?(key)
|
104
|
+
|
105
|
+
# We have to do this:
|
106
|
+
!get(key).nil?
|
107
|
+
end
|
108
|
+
|
39
109
|
# Begin entry into a named thread local stack.
|
40
110
|
#
|
41
111
|
# @example Begin entry into the stack.
|
@@ -55,7 +125,7 @@ module Mongoid
|
|
55
125
|
#
|
56
126
|
# @return [ String | Symbol ] The override.
|
57
127
|
def database_override
|
58
|
-
|
128
|
+
get(DATABASE_OVERRIDE_KEY)
|
59
129
|
end
|
60
130
|
|
61
131
|
# Set the global database override.
|
@@ -67,7 +137,7 @@ module Mongoid
|
|
67
137
|
#
|
68
138
|
# @return [ String | Symbol ] The override.
|
69
139
|
def database_override=(name)
|
70
|
-
|
140
|
+
set(DATABASE_OVERRIDE_KEY, name)
|
71
141
|
end
|
72
142
|
|
73
143
|
# Are in the middle of executing the named stack
|
@@ -103,7 +173,7 @@ module Mongoid
|
|
103
173
|
#
|
104
174
|
# @return [ Array ] The stack.
|
105
175
|
def stack(name)
|
106
|
-
|
176
|
+
get(STACK_KEYS[name]) { [] }
|
107
177
|
end
|
108
178
|
|
109
179
|
# Begin autosaving a document on the current thread.
|
@@ -177,7 +247,7 @@ module Mongoid
|
|
177
247
|
#
|
178
248
|
# @return [ String | Symbol ] The override.
|
179
249
|
def client_override
|
180
|
-
|
250
|
+
get(CLIENT_OVERRIDE_KEY)
|
181
251
|
end
|
182
252
|
|
183
253
|
# Set the global client override.
|
@@ -189,7 +259,7 @@ module Mongoid
|
|
189
259
|
#
|
190
260
|
# @return [ String | Symbol ] The override.
|
191
261
|
def client_override=(name)
|
192
|
-
|
262
|
+
set(CLIENT_OVERRIDE_KEY, name)
|
193
263
|
end
|
194
264
|
|
195
265
|
# Get the current Mongoid scope.
|
@@ -202,12 +272,12 @@ module Mongoid
|
|
202
272
|
#
|
203
273
|
# @return [ Criteria ] The scope.
|
204
274
|
def current_scope(klass = nil)
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
]
|
275
|
+
current_scope = get(CURRENT_SCOPE_KEY)
|
276
|
+
|
277
|
+
if klass && current_scope.respond_to?(:keys)
|
278
|
+
current_scope[current_scope.keys.find { |k| k <= klass }]
|
209
279
|
else
|
210
|
-
|
280
|
+
current_scope
|
211
281
|
end
|
212
282
|
end
|
213
283
|
|
@@ -220,7 +290,7 @@ module Mongoid
|
|
220
290
|
#
|
221
291
|
# @return [ Criteria ] The scope.
|
222
292
|
def current_scope=(scope)
|
223
|
-
|
293
|
+
set(CURRENT_SCOPE_KEY, scope)
|
224
294
|
end
|
225
295
|
|
226
296
|
# Set the current Mongoid scope. Safe for multi-model scope chaining.
|
@@ -236,8 +306,8 @@ module Mongoid
|
|
236
306
|
if scope.nil?
|
237
307
|
unset_current_scope(klass)
|
238
308
|
else
|
239
|
-
|
240
|
-
|
309
|
+
current_scope = get(CURRENT_SCOPE_KEY) { {} }
|
310
|
+
current_scope[klass] = scope
|
241
311
|
end
|
242
312
|
end
|
243
313
|
|
@@ -284,7 +354,7 @@ module Mongoid
|
|
284
354
|
#
|
285
355
|
# @return [ Hash ] The current autosaves.
|
286
356
|
def autosaves
|
287
|
-
|
357
|
+
get(AUTOSAVES_KEY) { {} }
|
288
358
|
end
|
289
359
|
|
290
360
|
# Get all validations on the current thread.
|
@@ -294,7 +364,7 @@ module Mongoid
|
|
294
364
|
#
|
295
365
|
# @return [ Hash ] The current validations.
|
296
366
|
def validations
|
297
|
-
|
367
|
+
get(VALIDATIONS_KEY) { {} }
|
298
368
|
end
|
299
369
|
|
300
370
|
# Get all autosaves on the current thread for the class.
|
@@ -376,9 +446,7 @@ module Mongoid
|
|
376
446
|
# @return [ Set<Mongoid::Document> ] Collection of modified documents before
|
377
447
|
# it was cleared.
|
378
448
|
def clear_modified_documents(session)
|
379
|
-
modified_documents[
|
380
|
-
ensure
|
381
|
-
modified_documents[session].clear
|
449
|
+
modified_documents.delete(session) || []
|
382
450
|
end
|
383
451
|
|
384
452
|
# Queries whether document callbacks should be executed by default for the
|
@@ -390,8 +458,8 @@ module Mongoid
|
|
390
458
|
# @return [ true | false ] Whether or not document callbacks should be
|
391
459
|
# executed by default.
|
392
460
|
def execute_callbacks?
|
393
|
-
if
|
394
|
-
|
461
|
+
if has?(EXECUTE_CALLBACKS)
|
462
|
+
get(EXECUTE_CALLBACKS)
|
395
463
|
else
|
396
464
|
true
|
397
465
|
end
|
@@ -404,7 +472,7 @@ module Mongoid
|
|
404
472
|
# @param flag [ true | false ] Whether or not document callbacks should be
|
405
473
|
# executed by default.
|
406
474
|
def execute_callbacks=(flag)
|
407
|
-
|
475
|
+
set(EXECUTE_CALLBACKS, flag)
|
408
476
|
end
|
409
477
|
|
410
478
|
# Returns the thread store of sessions.
|
@@ -413,7 +481,7 @@ module Mongoid
|
|
413
481
|
#
|
414
482
|
# @api private
|
415
483
|
def sessions
|
416
|
-
|
484
|
+
get(SESSIONS_KEY) { {}.compare_by_identity }
|
417
485
|
end
|
418
486
|
|
419
487
|
# Returns the thread store of modified documents.
|
@@ -423,9 +491,7 @@ module Mongoid
|
|
423
491
|
#
|
424
492
|
# @api private
|
425
493
|
def modified_documents
|
426
|
-
|
427
|
-
h[k] = Set.new
|
428
|
-
end
|
494
|
+
get(MODIFIED_DOCUMENTS_KEY) { Hash.new { |h, k| h[k] = Set.new } }
|
429
495
|
end
|
430
496
|
|
431
497
|
private
|
@@ -435,10 +501,12 @@ module Mongoid
|
|
435
501
|
#
|
436
502
|
# @param klass [ Class ] the class to remove from the current scope.
|
437
503
|
def unset_current_scope(klass)
|
438
|
-
return unless
|
504
|
+
return unless has?(CURRENT_SCOPE_KEY)
|
505
|
+
|
506
|
+
scope = get(CURRENT_SCOPE_KEY)
|
507
|
+
scope.delete(klass)
|
439
508
|
|
440
|
-
|
441
|
-
Thread.current[CURRENT_SCOPE_KEY] = nil if Thread.current[CURRENT_SCOPE_KEY].empty?
|
509
|
+
delete(CURRENT_SCOPE_KEY) if scope.empty?
|
442
510
|
end
|
443
511
|
end
|
444
512
|
end
|
@@ -46,6 +46,9 @@ module Mongoid
|
|
46
46
|
class << self
|
47
47
|
extend Forwardable
|
48
48
|
|
49
|
+
# The key to use to store the timeless table
|
50
|
+
TIMELESS_TABLE_KEY = '[mongoid]:timeless'
|
51
|
+
|
49
52
|
# Returns the in-memory thread cache of classes
|
50
53
|
# for which to skip timestamping.
|
51
54
|
#
|
@@ -53,7 +56,7 @@ module Mongoid
|
|
53
56
|
#
|
54
57
|
# @api private
|
55
58
|
def timeless_table
|
56
|
-
|
59
|
+
Threaded.get(TIMELESS_TABLE_KEY) { Hash.new }
|
57
60
|
end
|
58
61
|
|
59
62
|
def_delegators :timeless_table, :[]=, :[]
|
data/lib/mongoid/touchable.rb
CHANGED
@@ -195,7 +195,7 @@ module Mongoid
|
|
195
195
|
# @return [ Hash ] The hash that contains touch callback suppression
|
196
196
|
# statuses
|
197
197
|
def touch_callback_statuses
|
198
|
-
|
198
|
+
Threaded.get(SUPPRESS_TOUCH_CALLBACKS_KEY) { {} }
|
199
199
|
end
|
200
200
|
|
201
201
|
# Define the method that will get called for touching belongs_to
|
data/lib/mongoid/traversable.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'mongoid/fields/validators/macro'
|
4
|
+
require 'mongoid/model_resolver'
|
4
5
|
|
5
6
|
module Mongoid
|
6
7
|
# Mixin module included in Mongoid::Document to provide behavior
|
@@ -32,6 +33,10 @@ module Mongoid
|
|
32
33
|
# rubocop:disable Metrics/AbcSize
|
33
34
|
def inherited(subclass)
|
34
35
|
super
|
36
|
+
|
37
|
+
# Register the new subclass with the resolver subsystem
|
38
|
+
Mongoid::ModelResolver.register(subclass)
|
39
|
+
|
35
40
|
@_type = nil
|
36
41
|
subclass.aliased_fields = aliased_fields.dup
|
37
42
|
subclass.localized_fields = localized_fields.dup
|
@@ -100,7 +105,11 @@ module Mongoid
|
|
100
105
|
if value
|
101
106
|
Mongoid::Fields::Validators::Macro.validate_field_name(self, value)
|
102
107
|
value = value.to_s
|
103
|
-
|
108
|
+
if defined?(::ActiveSupport::ClassAttribute)
|
109
|
+
::ActiveSupport::ClassAttribute.redefine(self, 'discriminator_key', value)
|
110
|
+
else
|
111
|
+
super
|
112
|
+
end
|
104
113
|
else
|
105
114
|
# When discriminator key is set to nil, replace the class's definition
|
106
115
|
# of the discriminator key reader (provided by class_attribute earlier)
|
@@ -114,7 +123,7 @@ module Mongoid
|
|
114
123
|
# an existing field.
|
115
124
|
# This condition also checks if the class has any descendants, because
|
116
125
|
# if it doesn't then it doesn't need a discriminator key.
|
117
|
-
return
|
126
|
+
return if fields.key?(discriminator_key) || descendants.empty?
|
118
127
|
|
119
128
|
default_proc = -> { self.class.discriminator_value }
|
120
129
|
field(discriminator_key, default: default_proc, type: String)
|
@@ -70,13 +70,16 @@ module Mongoid
|
|
70
70
|
# Now, treating the target as an array, look at each element
|
71
71
|
# and see if it is valid, but only if it has already been
|
72
72
|
# persisted, or changed, and hasn't been flagged for destroy.
|
73
|
-
|
73
|
+
#
|
74
|
+
# use map.all? instead of just all?, because all? will do short-circuit
|
75
|
+
# evaluation and terminate on the first failed validation.
|
76
|
+
list.map do |value|
|
74
77
|
if value && !value.flagged_for_destroy? && (!value.persisted? || value.changed?)
|
75
78
|
value.validated? ? true : value.valid?
|
76
79
|
else
|
77
80
|
true
|
78
81
|
end
|
79
|
-
end
|
82
|
+
end.all?
|
80
83
|
end
|
81
84
|
|
82
85
|
document.errors.add(attribute, :invalid) unless valid
|
data/lib/mongoid/version.rb
CHANGED
@@ -2,31 +2,35 @@
|
|
2
2
|
# rubocop:todo all
|
3
3
|
|
4
4
|
require 'spec_helper'
|
5
|
-
|
6
|
-
require '
|
5
|
+
begin
|
6
|
+
require 'active_job'
|
7
|
+
require 'mongoid/railties/bson_object_id_serializer'
|
7
8
|
|
8
|
-
describe 'ActiveJob Serialization' do
|
9
|
-
|
9
|
+
describe 'ActiveJob Serialization' do
|
10
|
+
skip unless defined?(ActiveJob)
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
class TestBsonObjectIdSerializerJob < ActiveJob::Base
|
13
|
+
def perform(*args)
|
14
|
+
args
|
15
|
+
end
|
14
16
|
end
|
15
|
-
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
let(:band) do
|
19
|
+
Band.create!
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
before do
|
23
|
+
ActiveJob::Serializers.add_serializers(
|
24
|
+
[::Mongoid::Railties::ActiveJobSerializers::BsonObjectIdSerializer]
|
25
|
+
)
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
it 'serializes and deserializes BSON::ObjectId' do
|
29
|
+
expect do
|
30
|
+
TestBsonObjectIdSerializerJob.perform_later(band.id)
|
31
|
+
end.not_to raise_error
|
32
|
+
end
|
31
33
|
end
|
34
|
+
rescue LoadError
|
35
|
+
RSpec.context.skip 'This test requires active_job'
|
32
36
|
end
|