mongoid 9.0.2 → 9.0.4
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/attributes/readonly.rb +8 -3
- data/lib/mongoid/clients/options.rb +14 -1
- data/lib/mongoid/clients/sessions.rb +1 -0
- data/lib/mongoid/criteria/queryable/selectable.rb +1 -1
- data/lib/mongoid/equality.rb +1 -0
- data/lib/mongoid/loadable.rb +72 -8
- data/lib/mongoid/matcher.rb +15 -1
- data/lib/mongoid/persistence_context.rb +14 -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 +25 -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/mongoid/association/referenced/belongs_to/proxy_spec.rb +4 -0
- data/spec/mongoid/attributes/readonly_spec.rb +19 -0
- data/spec/mongoid/clients/options_spec.rb +127 -2
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +29 -0
- data/spec/mongoid/equality_spec.rb +6 -0
- data/spec/mongoid/interceptable_spec.rb +12 -0
- data/spec/mongoid/interceptable_spec_models.rb +12 -0
- data/spec/mongoid/loadable_spec.rb +86 -0
- data/spec/mongoid/persistence_context_spec.rb +39 -0
- data/spec/mongoid/railties/bson_object_id_serializer_spec.rb +18 -12
- 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 +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ac7ac8e60ba9d953a5a809d17b7fca7a2501988cdec50d12348af3b7022f615
|
4
|
+
data.tar.gz: 27a2bceb132e4f6b33d8be6b70ac8074b8de421c5c1efdb03f3ad2fc97d62364
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31cea6e77afe05358ff9cdaf5bc861807a93ce9c89e7cfd9209c0f35a2df816fb8d4d595faafbab2665b2dab776f523d0b96eece4b249626f976ec685765d5a5
|
7
|
+
data.tar.gz: 1367fb446dae452b73227c099e72ed2f13bd2702434e8050c09f3c1ae2ad97b5346371252ce3cfa3442151353bd8c8ef9a409cd2de75edb7cdf20ff3322107c7
|
@@ -23,7 +23,7 @@ module Mongoid
|
|
23
23
|
# @return [ true | false ] If the document is new, or if the field is not
|
24
24
|
# readonly.
|
25
25
|
def attribute_writable?(name)
|
26
|
-
new_record? || (!readonly_attributes.include?(name) && _loaded?(name))
|
26
|
+
new_record? || (!self.class.readonly_attributes.include?(name) && _loaded?(name))
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
@@ -63,12 +63,17 @@ module Mongoid
|
|
63
63
|
# end
|
64
64
|
#
|
65
65
|
# @param [ Symbol... ] *names The names of the fields.
|
66
|
+
# @note When a parent class contains readonly attributes and is then
|
67
|
+
# inherited by a child class, the child class will inherit the
|
68
|
+
# parent's readonly attributes at the time of its creation.
|
69
|
+
# Updating the parent does not propagate down to child classes after wards.
|
66
70
|
def attr_readonly(*names)
|
71
|
+
self.readonly_attributes = self.readonly_attributes.dup
|
67
72
|
names.each do |name|
|
68
|
-
readonly_attributes << database_field_name(name)
|
73
|
+
self.readonly_attributes << database_field_name(name)
|
69
74
|
end
|
70
75
|
end
|
71
76
|
end
|
72
77
|
end
|
73
78
|
end
|
74
|
-
end
|
79
|
+
end
|
@@ -86,7 +86,7 @@ module Mongoid
|
|
86
86
|
else
|
87
87
|
PersistenceContext.get(self) ||
|
88
88
|
PersistenceContext.get(self.class) ||
|
89
|
-
PersistenceContext.new(self.class,
|
89
|
+
PersistenceContext.new(self.class, default_storage_options)
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
@@ -112,6 +112,19 @@ module Mongoid
|
|
112
112
|
|
113
113
|
private
|
114
114
|
|
115
|
+
def default_storage_options
|
116
|
+
# Nothing is overridden, we use either the default storage_options
|
117
|
+
# or storage_options defined for the document class.
|
118
|
+
return storage_options if Threaded.client_override.nil? && Threaded.database_override.nil?
|
119
|
+
|
120
|
+
storage_options.tap do |opts|
|
121
|
+
# Globally overridden client replaces client defined for the document class.
|
122
|
+
opts[:client] = Threaded.client_override unless Threaded.client_override.nil?
|
123
|
+
# Globally overridden database replaces database defined for the document class.
|
124
|
+
opts[:database] = Threaded.database_override unless Threaded.database_override.nil?
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
115
128
|
def set_persistence_context(options_or_context)
|
116
129
|
PersistenceContext.set(self, options_or_context)
|
117
130
|
end
|
@@ -553,7 +553,7 @@ module Mongoid
|
|
553
553
|
# @return [ Selectable ] The new selectable.
|
554
554
|
def not(*criteria)
|
555
555
|
if criteria.empty?
|
556
|
-
dup.tap { |query| query.negating =
|
556
|
+
dup.tap { |query| query.negating = !query.negating }
|
557
557
|
else
|
558
558
|
criteria.compact.inject(self.clone) do |c, new_s|
|
559
559
|
if new_s.is_a?(Selectable)
|
data/lib/mongoid/equality.rb
CHANGED
data/lib/mongoid/loadable.rb
CHANGED
@@ -10,6 +10,13 @@ module Mongoid
|
|
10
10
|
# (See #model_paths.)
|
11
11
|
DEFAULT_MODEL_PATHS = %w( ./app/models ./lib/models ).freeze
|
12
12
|
|
13
|
+
# The default list of glob patterns that match paths to ignore when loading
|
14
|
+
# models. Defaults to '*/models/concerns/*', which Rails uses for extensions
|
15
|
+
# to models (and which cause errors when loaded out of order).
|
16
|
+
#
|
17
|
+
# See #ignore_patterns.
|
18
|
+
DEFAULT_IGNORE_PATTERNS = %w( */models/concerns/* ).freeze
|
19
|
+
|
13
20
|
# Search a list of model paths to get every model and require it, so
|
14
21
|
# that indexing and inheritance work in both development and production
|
15
22
|
# with the same results.
|
@@ -24,17 +31,47 @@ module Mongoid
|
|
24
31
|
# for model files. These must either be absolute paths, or relative to
|
25
32
|
# the current working directory.
|
26
33
|
def load_models(paths = model_paths)
|
27
|
-
|
28
|
-
|
29
|
-
|
34
|
+
files = files_under_paths(paths)
|
35
|
+
|
36
|
+
files.sort.each do |file|
|
37
|
+
load_model(file)
|
38
|
+
end
|
39
|
+
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
# Given a list of paths, return all ruby files under that path (or, if
|
44
|
+
# `preload_models` is a list of model names, returns only the files for
|
45
|
+
# those named models).
|
46
|
+
#
|
47
|
+
# @param [ Array<String> ] paths the list of paths to search
|
48
|
+
#
|
49
|
+
# @return [ Array<String> ] the normalized file names, suitable for loading
|
50
|
+
# via `require_dependency` or `require`.
|
51
|
+
def files_under_paths(paths)
|
52
|
+
paths.flat_map { |path| files_under_path(path) }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Given a single path, returns all ruby files under that path (or, if
|
56
|
+
# `preload_models` is a list of model names, returns only the files for
|
57
|
+
# those named models).
|
58
|
+
#
|
59
|
+
# @param [ String ] path the path to search
|
60
|
+
#
|
61
|
+
# @return [ Array<String> ] the normalized file names, suitable for loading
|
62
|
+
# via `require_dependency` or `require`.
|
63
|
+
def files_under_path(path)
|
64
|
+
files = if preload_models.resizable?
|
65
|
+
preload_models.
|
66
|
+
map { |model| "#{path}/#{model.underscore}.rb" }.
|
67
|
+
select { |file_name| File.exists?(file_name) }
|
30
68
|
else
|
31
|
-
|
69
|
+
Dir.glob("#{path}/**/*.rb").
|
70
|
+
reject { |file_name| ignored?(file_name) }
|
32
71
|
end
|
33
72
|
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
end
|
73
|
+
# strip the path and the suffix from each entry
|
74
|
+
files.map { |file| file.gsub(/^#{path}\// , "").gsub(/\.rb$/, "") }
|
38
75
|
end
|
39
76
|
|
40
77
|
# A convenience method for loading a model's file. If Rails'
|
@@ -71,6 +108,14 @@ module Mongoid
|
|
71
108
|
DEFAULT_MODEL_PATHS
|
72
109
|
end
|
73
110
|
|
111
|
+
# Returns the array of glob patterns that determine whether a given
|
112
|
+
# path should be ignored by the model loader.
|
113
|
+
#
|
114
|
+
# @return [ Array<String> ] the array of ignore patterns
|
115
|
+
def ignore_patterns
|
116
|
+
@ignore_patterns ||= DEFAULT_IGNORE_PATTERNS.dup
|
117
|
+
end
|
118
|
+
|
74
119
|
# Sets the model paths to the given array of paths. These are the paths
|
75
120
|
# where the application's model definitions are located.
|
76
121
|
#
|
@@ -78,6 +123,25 @@ module Mongoid
|
|
78
123
|
def model_paths=(paths)
|
79
124
|
@model_paths = paths
|
80
125
|
end
|
126
|
+
|
127
|
+
# Sets the ignore patterns to the given array of patterns. These are glob
|
128
|
+
# patterns that determine whether a given path should be ignored by the
|
129
|
+
# model loader or not.
|
130
|
+
#
|
131
|
+
# @param [ Array<String> ] patterns The list of glob patterns
|
132
|
+
def ignore_patterns=(patterns)
|
133
|
+
@ignore_patterns = patterns
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns true if the given file path matches any of the ignore patterns.
|
137
|
+
#
|
138
|
+
# @param [ String ] file_path The file path to consider
|
139
|
+
#
|
140
|
+
# @return [ true | false ] whether or not the given file path should be
|
141
|
+
# ignored.
|
142
|
+
def ignored?(file_path)
|
143
|
+
ignore_patterns.any? { |pattern| File.fnmatch?(pattern, file_path) }
|
144
|
+
end
|
81
145
|
end
|
82
146
|
|
83
147
|
end
|
data/lib/mongoid/matcher.rb
CHANGED
@@ -39,11 +39,25 @@ module Mongoid
|
|
39
39
|
# from and behaves identically to association traversal for the purposes
|
40
40
|
# of, for example, subsequent array element retrieval.
|
41
41
|
#
|
42
|
-
# @param [ Document | Hash ] document The document to extract from.
|
42
|
+
# @param [ Document | Hash | String ] document The document to extract from.
|
43
43
|
# @param [ String ] key The key path to extract.
|
44
44
|
#
|
45
45
|
# @return [ Object | Array ] Field value or values.
|
46
46
|
module_function def extract_attribute(document, key)
|
47
|
+
# The matcher system will wind up sending atomic values to this as well,
|
48
|
+
# when attepting to match more complex types. If anything other than a
|
49
|
+
# Document or a Hash is given, we'll short-circuit the logic and just
|
50
|
+
# return an empty array.
|
51
|
+
return [] unless document.is_a?(Hash) || document.is_a?(Document)
|
52
|
+
|
53
|
+
# Performance optimization; if the key does not include a '.' character,
|
54
|
+
# it must reference an immediate attribute of the document.
|
55
|
+
unless key.include?('.')
|
56
|
+
hash = document.respond_to?(:attributes) ? document.attributes : document
|
57
|
+
key = find_exact_key(hash, key)
|
58
|
+
return key ? [ hash[key] ] : []
|
59
|
+
end
|
60
|
+
|
47
61
|
if document.respond_to?(:as_attributes, true)
|
48
62
|
# If a document has hash fields, as_attributes would keep those fields
|
49
63
|
# as Hash instances which do not offer indifferent access.
|
@@ -117,12 +117,15 @@ module Mongoid
|
|
117
117
|
def client
|
118
118
|
@client ||= begin
|
119
119
|
client = Clients.with_name(client_name)
|
120
|
+
options = client_options
|
121
|
+
|
120
122
|
if database_name_option
|
121
123
|
client = client.use(database_name)
|
124
|
+
options = options.except(:database, 'database')
|
122
125
|
end
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
+
|
127
|
+
client = client.with(options) unless options.empty?
|
128
|
+
|
126
129
|
client
|
127
130
|
end
|
128
131
|
end
|
@@ -135,7 +138,7 @@ module Mongoid
|
|
135
138
|
# @return [ Symbol ] The client name for this persistence
|
136
139
|
# context.
|
137
140
|
def client_name
|
138
|
-
@client_name ||= options[:client] ||
|
141
|
+
@client_name ||= __evaluate__(options[:client]) ||
|
139
142
|
Threaded.client_override ||
|
140
143
|
__evaluate__(storage_options[:client])
|
141
144
|
end
|
@@ -282,6 +285,10 @@ module Mongoid
|
|
282
285
|
# @api private
|
283
286
|
PERSISTENCE_CONTEXT_KEY = :"[mongoid]:persistence_context"
|
284
287
|
|
288
|
+
def context_store
|
289
|
+
Threaded.get(PERSISTENCE_CONTEXT_KEY) { {} }
|
290
|
+
end
|
291
|
+
|
285
292
|
# Get the persistence context for a given object from the thread local
|
286
293
|
# storage.
|
287
294
|
#
|
@@ -292,8 +299,7 @@ module Mongoid
|
|
292
299
|
#
|
293
300
|
# @api private
|
294
301
|
def get_context(object)
|
295
|
-
|
296
|
-
Thread.current[PERSISTENCE_CONTEXT_KEY][object.object_id]
|
302
|
+
context_store[object.object_id]
|
297
303
|
end
|
298
304
|
|
299
305
|
# Store persistence context for a given object in the thread local
|
@@ -305,10 +311,9 @@ module Mongoid
|
|
305
311
|
# @api private
|
306
312
|
def store_context(object, context)
|
307
313
|
if context.nil?
|
308
|
-
|
314
|
+
context_store.delete(object.object_id)
|
309
315
|
else
|
310
|
-
|
311
|
-
Thread.current[PERSISTENCE_CONTEXT_KEY][object.object_id] = context
|
316
|
+
context_store[object.object_id] = context
|
312
317
|
end
|
313
318
|
end
|
314
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
@@ -8,6 +8,29 @@ module Mongoid
|
|
8
8
|
# around traversing the document graph.
|
9
9
|
module Traversable
|
10
10
|
extend ActiveSupport::Concern
|
11
|
+
# This code is extracted from ActiveSupport so that we do not depend on
|
12
|
+
# their private API that may change at any time.
|
13
|
+
# This code should be reviewed and maybe removed when implementing
|
14
|
+
# https://jira.mongodb.org/browse/MONGOID-5832
|
15
|
+
class << self
|
16
|
+
# @api private
|
17
|
+
def __redefine(owner, name, value)
|
18
|
+
if owner.singleton_class?
|
19
|
+
owner.redefine_method(name) { value }
|
20
|
+
owner.send(:public, name)
|
21
|
+
end
|
22
|
+
owner.redefine_singleton_method(name) { value }
|
23
|
+
owner.singleton_class.send(:public, name)
|
24
|
+
owner.redefine_singleton_method("#{name}=") do |new_value|
|
25
|
+
if owner.equal?(self)
|
26
|
+
value = new_value
|
27
|
+
else
|
28
|
+
::Mongoid::Traversable.redefine(self, name, new_value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
owner.singleton_class.send(:public, "#{name}=")
|
32
|
+
end
|
33
|
+
end
|
11
34
|
|
12
35
|
# Class-level methods for the Traversable behavior.
|
13
36
|
module ClassMethods
|
@@ -105,7 +128,7 @@ module Mongoid
|
|
105
128
|
if value
|
106
129
|
Mongoid::Fields::Validators::Macro.validate_field_name(self, value)
|
107
130
|
value = value.to_s
|
108
|
-
|
131
|
+
::Mongoid::Traversable.__redefine(self, 'discriminator_key', value)
|
109
132
|
else
|
110
133
|
# When discriminator key is set to nil, replace the class's definition
|
111
134
|
# of the discriminator key reader (provided by class_attribute earlier)
|
@@ -119,7 +142,7 @@ module Mongoid
|
|
119
142
|
# an existing field.
|
120
143
|
# This condition also checks if the class has any descendants, because
|
121
144
|
# if it doesn't then it doesn't need a discriminator key.
|
122
|
-
return
|
145
|
+
return if fields.key?(discriminator_key) || descendants.empty?
|
123
146
|
|
124
147
|
default_proc = -> { self.class.discriminator_value }
|
125
148
|
field(discriminator_key, default: default_proc, type: String)
|