mongoid 8.0.8 → 8.0.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/Rakefile +65 -41
- data/lib/mongoid/association/accessors.rb +5 -1
- data/lib/mongoid/association/eager_loadable.rb +3 -0
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +21 -4
- data/lib/mongoid/config.rb +10 -0
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -1
- data/lib/mongoid/document.rb +8 -1
- data/lib/mongoid/fields.rb +11 -6
- data/lib/mongoid/interceptable.rb +10 -8
- data/lib/mongoid/timestamps/created.rb +8 -1
- data/lib/mongoid/traversable.rb +12 -0
- data/lib/mongoid/validatable/associated.rb +6 -3
- data/lib/mongoid/version.rb +1 -1
- data/spec/integration/app_spec.rb +4 -0
- data/spec/integration/callbacks_models.rb +37 -0
- data/spec/integration/callbacks_spec.rb +27 -0
- data/spec/mongoid/association/eager_spec.rb +24 -2
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +4 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +28 -37
- data/spec/mongoid/association_spec.rb +60 -0
- data/spec/mongoid/document_spec.rb +27 -0
- data/spec/mongoid/interceptable_spec.rb +100 -0
- data/spec/mongoid/interceptable_spec_models.rb +51 -111
- data/spec/mongoid/serializable_spec.rb +14 -14
- data/spec/mongoid/timestamps/created_spec.rb +23 -0
- data/spec/mongoid/validatable/associated_spec.rb +14 -4
- data/spec/support/models/book.rb +1 -0
- data/spec/support/models/cover.rb +10 -0
- metadata +6 -80
- checksums.yaml.gz.sig +0 -0
- data/spec/shared/LICENSE +0 -20
- data/spec/shared/bin/get-mongodb-download-url +0 -17
- data/spec/shared/bin/s3-copy +0 -45
- data/spec/shared/bin/s3-upload +0 -69
- data/spec/shared/lib/mrss/child_process_helper.rb +0 -80
- data/spec/shared/lib/mrss/cluster_config.rb +0 -231
- data/spec/shared/lib/mrss/constraints.rb +0 -378
- data/spec/shared/lib/mrss/docker_runner.rb +0 -298
- data/spec/shared/lib/mrss/eg_config_utils.rb +0 -51
- data/spec/shared/lib/mrss/event_subscriber.rb +0 -210
- data/spec/shared/lib/mrss/lite_constraints.rb +0 -238
- data/spec/shared/lib/mrss/server_version_registry.rb +0 -113
- data/spec/shared/lib/mrss/session_registry.rb +0 -69
- data/spec/shared/lib/mrss/session_registry_legacy.rb +0 -60
- data/spec/shared/lib/mrss/spec_organizer.rb +0 -179
- data/spec/shared/lib/mrss/utils.rb +0 -37
- data/spec/shared/share/Dockerfile.erb +0 -321
- data/spec/shared/share/haproxy-1.conf +0 -16
- data/spec/shared/share/haproxy-2.conf +0 -17
- data/spec/shared/shlib/config.sh +0 -27
- data/spec/shared/shlib/distro.sh +0 -74
- data/spec/shared/shlib/server.sh +0 -416
- data/spec/shared/shlib/set_env.sh +0 -169
- data.tar.gz.sig +0 -0
- 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: 5d5d57d80bf503ada4f229db360fee76b689f1224292a05ce8b9e2e1f2768f17
|
4
|
+
data.tar.gz: 409bfdfa5c3f91cfc75429569148cbff7bc19716193ac2af3d101f91647b7ea8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2aa57a75a92f7a03d872f28a0be8cfdd800d2917a9893b2cb4101cedcc1196c02c2e9591e3de67580b00b06626ea16bdf8aa742cc5752a806581e88a186410de
|
7
|
+
data.tar.gz: 725b89395a8d8126c196bd3ed42f02dc44c9e019247364f4fcc2d5587cf742a2ba3e9c27cafface3ea13712e2f17ea0fab081a8177b52299ed36b74b35a49347
|
data/Rakefile
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "bundler"
|
4
|
-
require "bundler/gem_tasks"
|
5
4
|
Bundler.setup
|
6
5
|
|
7
6
|
ROOT = File.expand_path(File.join(File.dirname(__FILE__)))
|
@@ -10,34 +9,53 @@ $: << File.join(ROOT, 'spec/shared/lib')
|
|
10
9
|
|
11
10
|
require "rake"
|
12
11
|
require "rspec/core/rake_task"
|
13
|
-
require 'mrss/spec_organizer'
|
14
|
-
require 'rubygems/package'
|
15
|
-
require 'rubygems/security/policies'
|
16
|
-
|
17
|
-
def signed_gem?(path_to_gem)
|
18
|
-
Gem::Package.new(path_to_gem, Gem::Security::HighSecurity).verify
|
19
|
-
true
|
20
|
-
rescue Gem::Security::Exception => e
|
21
|
-
false
|
22
|
-
end
|
23
|
-
|
24
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
25
|
-
require "mongoid/version"
|
26
|
-
|
27
|
-
tasks = Rake.application.instance_variable_get('@tasks')
|
28
|
-
tasks['release:do'] = tasks.delete('release')
|
29
12
|
|
30
|
-
task
|
13
|
+
# stands in for the Bundler-provided `build` task, which builds the
|
14
|
+
# gem for this project. Our release process builds the gems in a
|
15
|
+
# particular way, in a GitHub action. This task is just to help remind
|
16
|
+
# developers of that fact.
|
31
17
|
task :build do
|
32
|
-
|
18
|
+
abort <<~WARNING
|
19
|
+
`rake build` does nothing in this project. The gem must be built via
|
20
|
+
the `Mongoid Release` action on GitHub, which is triggered manually when
|
21
|
+
a new release is ready.
|
22
|
+
WARNING
|
33
23
|
end
|
34
24
|
|
35
|
-
|
36
|
-
|
25
|
+
# `rake version` is used by the deployment system so get the release version
|
26
|
+
# of the product beng deployed. It must do nothing more than just print the
|
27
|
+
# product version number.
|
28
|
+
#
|
29
|
+
# See the mongodb-labs/driver-github-tools/ruby/publish Github action.
|
30
|
+
desc "Print the current value of Mongoid::VERSION"
|
31
|
+
task :version do
|
32
|
+
require 'mongoid/version'
|
33
|
+
|
34
|
+
puts Mongoid::VERSION
|
37
35
|
end
|
38
36
|
|
37
|
+
# overrides the default Bundler-provided `release` task, which also
|
38
|
+
# builds the gem. Our release process assumes the gem has already
|
39
|
+
# been built (and signed via GPG), so we just need `rake release` to
|
40
|
+
# push the gem to rubygems.
|
39
41
|
task :release do
|
40
|
-
|
42
|
+
require 'mongoid/version'
|
43
|
+
|
44
|
+
if ENV['GITHUB_ACTION'].nil?
|
45
|
+
abort <<~WARNING
|
46
|
+
`rake release` must be invoked from the `Mongoid Release` GitHub action,
|
47
|
+
and must not be invoked locally. This ensures the gem is properly signed
|
48
|
+
and distributed by the appropriate user.
|
49
|
+
|
50
|
+
Note that it is the `rubygems/release-gem@v1` step in the `Mongoid Release`
|
51
|
+
action that invokes this task. Do not rename or remove this task, or the
|
52
|
+
release-gem step will fail. Reimplement this task with caution.
|
53
|
+
|
54
|
+
mongoid-#{Mongoid::VERSION}.gem was NOT pushed to RubyGems.
|
55
|
+
WARNING
|
56
|
+
end
|
57
|
+
|
58
|
+
system 'gem', 'push', "mongoid-#{Mongoid::VERSION}.gem"
|
41
59
|
end
|
42
60
|
|
43
61
|
RSpec::Core::RakeTask.new("spec") do |spec|
|
@@ -64,6 +82,8 @@ RUN_PRIORITY = %i(
|
|
64
82
|
)
|
65
83
|
|
66
84
|
def spec_organizer
|
85
|
+
require 'mrss/spec_organizer'
|
86
|
+
|
67
87
|
Mrss::SpecOrganizer.new(
|
68
88
|
root: ROOT,
|
69
89
|
classifiers: CLASSIFIERS,
|
@@ -99,32 +119,36 @@ task :docs => 'docs:yard'
|
|
99
119
|
namespace :docs do
|
100
120
|
desc "Generate yard documention"
|
101
121
|
task :yard do
|
122
|
+
require "mongoid/version"
|
123
|
+
|
102
124
|
out = File.join('yard-docs', Mongoid::VERSION)
|
103
125
|
FileUtils.rm_rf(out)
|
104
126
|
system "yardoc -o #{out} --title mongoid-#{Mongoid::VERSION}"
|
105
127
|
end
|
106
128
|
end
|
107
129
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
130
|
+
desc 'Build and validate the evergreen config'
|
131
|
+
task eg: %w[ eg:build eg:validate ]
|
132
|
+
|
133
|
+
# 'eg' == 'evergreen', but evergreen is too many letters for convenience
|
134
|
+
namespace :eg do
|
135
|
+
desc 'Builds the .evergreen/config.yml file from the templates'
|
136
|
+
task :build do
|
137
|
+
ruby '.evergreen/update-evergreen-configs'
|
113
138
|
end
|
114
|
-
end
|
115
139
|
|
116
|
-
desc '
|
117
|
-
task :
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
140
|
+
desc 'Validates the .evergreen/config.yml file'
|
141
|
+
task :validate do
|
142
|
+
system 'evergreen validate --project mongoid .evergreen/config.yml'
|
143
|
+
end
|
144
|
+
|
145
|
+
desc 'Updates the evergreen executable to the latest available version'
|
146
|
+
task :update do
|
147
|
+
system 'evergreen get-update --install'
|
148
|
+
end
|
149
|
+
|
150
|
+
desc 'Runs the current branch as an evergreen patch'
|
151
|
+
task :patch do
|
152
|
+
system 'evergreen patch --uncommitted --project mongoid --browse --auto-description --yes'
|
129
153
|
end
|
130
154
|
end
|
@@ -115,7 +115,11 @@ module Mongoid
|
|
115
115
|
# during binding or when cascading callbacks. Whenever we retrieve
|
116
116
|
# associations within the codebase, we use without_autobuild.
|
117
117
|
if !without_autobuild? && association.embedded? && attribute_missing?(field_name)
|
118
|
-
|
118
|
+
# We always allow accessing the parent document of an embedded one.
|
119
|
+
try_get_parent = association.is_a?(
|
120
|
+
Mongoid::Association::Embedded::EmbeddedIn
|
121
|
+
) && field_name == association.key
|
122
|
+
raise ActiveModel::MissingAttributeError, "Missing attribute: '#{field_name}'" unless try_get_parent
|
119
123
|
end
|
120
124
|
|
121
125
|
if !reload && (value = ivar(name)) != false
|
@@ -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
|
|
data/lib/mongoid/config.rb
CHANGED
@@ -142,6 +142,16 @@ module Mongoid
|
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
145
|
+
# When this flag is true, callbacks for every embedded document will be
|
146
|
+
# called only once, even if the embedded document is embedded in multiple
|
147
|
+
# documents in the root document's dependencies graph.
|
148
|
+
# This will be the default in 9.0. Setting this flag to false restores the
|
149
|
+
# pre-9.0 behavior, where callbacks are called for every occurrence of an
|
150
|
+
# embedded document. The pre-9.0 behavior leads to a problem that for multi
|
151
|
+
# level nested documents callbacks are called multiple times.
|
152
|
+
# See https://jira.mongodb.org/browse/MONGOID-5542
|
153
|
+
option :prevent_multiple_calls_of_embedded_callbacks, default: false
|
154
|
+
|
145
155
|
# When this flag is true, callbacks for embedded documents will not be
|
146
156
|
# called. This is the default in 8.x, but will be changed to false in 9.0.
|
147
157
|
#
|
@@ -43,7 +43,21 @@ module Mongoid
|
|
43
43
|
#
|
44
44
|
# @return [ Object ] The converted number.
|
45
45
|
def __numeric__(object)
|
46
|
-
|
46
|
+
str = object.to_s
|
47
|
+
raise ArgumentError if str.empty?
|
48
|
+
|
49
|
+
# These requirements seem a bit odd, but they're explicitly specified in the tests,
|
50
|
+
# so we're obligated to keep them, for now. (This code was rewritten from a one-line
|
51
|
+
# regex, due to security concerns with a polynomial regex being used on uncontrolled
|
52
|
+
# data).
|
53
|
+
|
54
|
+
str = str.chop if str.end_with?('.')
|
55
|
+
return 0 if str.empty?
|
56
|
+
|
57
|
+
result = Integer(str) rescue Float(object)
|
58
|
+
|
59
|
+
integer = result.to_i
|
60
|
+
integer == result ? integer : result
|
47
61
|
end
|
48
62
|
|
49
63
|
# Evolve the object to an integer.
|
data/lib/mongoid/document.rb
CHANGED
@@ -133,7 +133,14 @@ module Mongoid
|
|
133
133
|
#
|
134
134
|
# @return [ Hash ] A hash of all attributes in the hierarchy.
|
135
135
|
def as_document
|
136
|
-
|
136
|
+
attrs = as_attributes
|
137
|
+
|
138
|
+
# legacy attributes have a tendency to leak internal state via
|
139
|
+
# `as_document`; we have to deep_dup the attributes here to prevent
|
140
|
+
# that.
|
141
|
+
attrs = attrs.deep_dup if Mongoid.legacy_attributes
|
142
|
+
|
143
|
+
BSON::Document.new(attrs)
|
137
144
|
end
|
138
145
|
|
139
146
|
# Calls #as_json on the document with additional, Mongoid-specific options.
|
data/lib/mongoid/fields.rb
CHANGED
@@ -47,6 +47,11 @@ module Mongoid
|
|
47
47
|
# @api private
|
48
48
|
INVALID_BSON_CLASSES = [ BSON::Decimal128, BSON::Int32, BSON::Int64 ].freeze
|
49
49
|
|
50
|
+
# The suffix for generated translated fields.
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
TRANSLATIONS_SFX = '_translations'
|
54
|
+
|
50
55
|
module ClassMethods
|
51
56
|
# Returns the list of id fields for this model class, as both strings
|
52
57
|
# and symbols.
|
@@ -99,8 +104,8 @@ module Mongoid
|
|
99
104
|
ar.each_with_index do |fn, i|
|
100
105
|
key = fn
|
101
106
|
unless klass.fields.key?(fn) || klass.relations.key?(fn)
|
102
|
-
if
|
103
|
-
key =
|
107
|
+
if fn.end_with?(TRANSLATIONS_SFX)
|
108
|
+
key = fn.delete_suffix(TRANSLATIONS_SFX)
|
104
109
|
else
|
105
110
|
key = fn
|
106
111
|
end
|
@@ -708,11 +713,11 @@ module Mongoid
|
|
708
713
|
# @param [ String ] meth The name of the method.
|
709
714
|
def create_translations_getter(name, meth)
|
710
715
|
generated_methods.module_eval do
|
711
|
-
re_define_method("#{meth}
|
716
|
+
re_define_method("#{meth}#{TRANSLATIONS_SFX}") do
|
712
717
|
attributes[name] ||= {}
|
713
718
|
attributes[name].with_indifferent_access
|
714
719
|
end
|
715
|
-
alias_method :"#{meth}_t", :"#{meth}
|
720
|
+
alias_method :"#{meth}_t", :"#{meth}#{TRANSLATIONS_SFX}"
|
716
721
|
end
|
717
722
|
end
|
718
723
|
|
@@ -726,14 +731,14 @@ module Mongoid
|
|
726
731
|
# @param [ Field ] field The field.
|
727
732
|
def create_translations_setter(name, meth, field)
|
728
733
|
generated_methods.module_eval do
|
729
|
-
re_define_method("#{meth}
|
734
|
+
re_define_method("#{meth}#{TRANSLATIONS_SFX}=") do |value|
|
730
735
|
attribute_will_change!(name)
|
731
736
|
value&.transform_values! do |_value|
|
732
737
|
field.type.mongoize(_value)
|
733
738
|
end
|
734
739
|
attributes[name] = value
|
735
740
|
end
|
736
|
-
alias_method :"#{meth}_t=", :"#{meth}
|
741
|
+
alias_method :"#{meth}_t=", :"#{meth}#{TRANSLATIONS_SFX}="
|
737
742
|
end
|
738
743
|
end
|
739
744
|
|
@@ -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
|
|
@@ -163,13 +167,14 @@ module Mongoid
|
|
163
167
|
# @api private
|
164
168
|
def _mongoid_run_child_callbacks_with_around(kind, children: nil, &block)
|
165
169
|
child, *tail = (children || cascadable_children(kind))
|
170
|
+
with_children = !Mongoid::Config.prevent_multiple_calls_of_embedded_callbacks
|
166
171
|
if child.nil?
|
167
172
|
block&.call
|
168
173
|
elsif tail.empty?
|
169
|
-
child.run_callbacks(child_callback_type(kind, child), &block)
|
174
|
+
child.run_callbacks(child_callback_type(kind, child), with_children: with_children, &block)
|
170
175
|
else
|
171
|
-
child.run_callbacks(child_callback_type(kind, child)) do
|
172
|
-
|
176
|
+
child.run_callbacks(child_callback_type(kind, child), with_children: with_children) do
|
177
|
+
_mongoid_run_child_callbacks(kind, children: tail, &block)
|
173
178
|
end
|
174
179
|
end
|
175
180
|
end
|
@@ -218,9 +223,6 @@ module Mongoid
|
|
218
223
|
return false if env.halted
|
219
224
|
env.value = !env.halted
|
220
225
|
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
226
|
end
|
225
227
|
callback_list
|
226
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
@@ -300,6 +300,18 @@ module Mongoid
|
|
300
300
|
!!(Mongoid::Document > superclass)
|
301
301
|
end
|
302
302
|
|
303
|
+
# Returns the root class of the STI tree that the current
|
304
|
+
# class participates in. If the class is not an STI subclass, this
|
305
|
+
# returns the class itself.
|
306
|
+
#
|
307
|
+
# @return [ Mongoid::Document ] the root of the STI tree
|
308
|
+
def root_class
|
309
|
+
root = self
|
310
|
+
root = root.superclass while root.hereditary?
|
311
|
+
|
312
|
+
root
|
313
|
+
end
|
314
|
+
|
303
315
|
# When inheriting, we want to copy the fields from the parent class and
|
304
316
|
# set the on the child to start, mimicking the behavior of the old
|
305
317
|
# class_inheritable_accessor that was deprecated in Rails edge.
|
@@ -69,13 +69,16 @@ module Mongoid
|
|
69
69
|
# Now, treating the target as an array, look at each element
|
70
70
|
# and see if it is valid, but only if it has already been
|
71
71
|
# persisted, or changed, and hasn't been flagged for destroy.
|
72
|
-
|
73
|
-
|
72
|
+
#
|
73
|
+
# use map.all? instead of just all?, because all? will do short-circuit
|
74
|
+
# evaluation and terminate on the first failed validation.
|
75
|
+
list.map do |value|
|
76
|
+
if value && !value.flagged_for_destroy?
|
74
77
|
value.validated? ? true : value.valid?
|
75
78
|
else
|
76
79
|
true
|
77
80
|
end
|
78
|
-
end
|
81
|
+
end.all?
|
79
82
|
end
|
80
83
|
|
81
84
|
document.errors.add(attribute, :invalid) unless valid
|
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'
|
@@ -153,3 +153,40 @@ class Building
|
|
153
153
|
|
154
154
|
has_and_belongs_to_many :architects, dependent: :nullify
|
155
155
|
end
|
156
|
+
|
157
|
+
class Root
|
158
|
+
include Mongoid::Document
|
159
|
+
embeds_many :embedded_once, cascade_callbacks: true
|
160
|
+
after_save :trace
|
161
|
+
|
162
|
+
attr_accessor :logger
|
163
|
+
|
164
|
+
def trace
|
165
|
+
logger << :root
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class EmbeddedOnce
|
170
|
+
include Mongoid::Document
|
171
|
+
embeds_many :embedded_twice, cascade_callbacks: true
|
172
|
+
embedded_in :root
|
173
|
+
after_save :trace
|
174
|
+
|
175
|
+
attr_accessor :logger
|
176
|
+
|
177
|
+
def trace
|
178
|
+
logger << :embedded_once
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class EmbeddedTwice
|
183
|
+
include Mongoid::Document
|
184
|
+
embedded_in :embedded_once
|
185
|
+
after_save :trace
|
186
|
+
|
187
|
+
attr_accessor :logger
|
188
|
+
|
189
|
+
def trace
|
190
|
+
logger << :embedded_twice
|
191
|
+
end
|
192
|
+
end
|
@@ -467,4 +467,31 @@ describe 'callbacks integration tests' do
|
|
467
467
|
expect { book.save! }.not_to raise_error(SystemStackError)
|
468
468
|
end
|
469
469
|
end
|
470
|
+
|
471
|
+
context 'nested embedded documents' do
|
472
|
+
config_override :prevent_multiple_calls_of_embedded_callbacks, true
|
473
|
+
|
474
|
+
let(:logger) { Array.new }
|
475
|
+
|
476
|
+
let(:root) do
|
477
|
+
Root.new(
|
478
|
+
embedded_once: [
|
479
|
+
EmbeddedOnce.new(
|
480
|
+
embedded_twice: [EmbeddedTwice.new]
|
481
|
+
)
|
482
|
+
]
|
483
|
+
)
|
484
|
+
end
|
485
|
+
|
486
|
+
before(:each) do
|
487
|
+
root.logger = logger
|
488
|
+
root.embedded_once.first.logger = logger
|
489
|
+
root.embedded_once.first.embedded_twice.first.logger = logger
|
490
|
+
end
|
491
|
+
|
492
|
+
it 'runs callbacks in the correct order' do
|
493
|
+
root.save!
|
494
|
+
expect(logger).to eq(%i[embedded_twice embedded_once root])
|
495
|
+
end
|
496
|
+
end
|
470
497
|
end
|
@@ -14,14 +14,36 @@ describe Mongoid::Association::EagerLoadable do
|
|
14
14
|
Mongoid::Contextual::Mongo.new(criteria)
|
15
15
|
end
|
16
16
|
|
17
|
+
let(:association_host) { Account }
|
18
|
+
|
17
19
|
let(:inclusions) do
|
18
20
|
includes.map do |key|
|
19
|
-
|
21
|
+
association_host.reflect_on_association(key)
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
25
|
let(:doc) { criteria.first }
|
24
26
|
|
27
|
+
context 'when root is an STI subclass' do
|
28
|
+
# Driver has_one Vehicle
|
29
|
+
# Vehicle belongs_to Driver
|
30
|
+
# Truck is a Vehicle
|
31
|
+
|
32
|
+
before do
|
33
|
+
Driver.create!(vehicle: Truck.new)
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:criteria) { Truck.all }
|
37
|
+
let(:includes) { %i[ driver ] }
|
38
|
+
let(:association_host) { Truck }
|
39
|
+
|
40
|
+
it 'preloads the driver' do
|
41
|
+
expect(doc.ivar(:driver)).to be false
|
42
|
+
context.preload(inclusions, [ doc ])
|
43
|
+
expect(doc.ivar(:driver)).to be == Driver.first
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
25
47
|
context "when belongs_to" do
|
26
48
|
|
27
49
|
let!(:account) do
|
@@ -42,7 +64,7 @@ describe Mongoid::Association::EagerLoadable do
|
|
42
64
|
it "preloads the parent" do
|
43
65
|
expect(doc.ivar(:person)).to be false
|
44
66
|
context.preload(inclusions, [doc])
|
45
|
-
expect(doc.ivar(:person)).to
|
67
|
+
expect(doc.ivar(:person)).to be == person
|
46
68
|
end
|
47
69
|
end
|
48
70
|
|
@@ -27,6 +27,10 @@ describe Mongoid::Association::Embedded::EmbedsMany do
|
|
27
27
|
expect(legislator.attributes.keys).to eq(['_id', 'a'])
|
28
28
|
end
|
29
29
|
|
30
|
+
it 'allows accessing the parent' do
|
31
|
+
expect { legislator.congress }.not_to raise_error
|
32
|
+
end
|
33
|
+
|
30
34
|
context 'when using only with $' do
|
31
35
|
before do
|
32
36
|
Patient.destroy_all
|
@@ -1757,43 +1757,6 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
|
|
1757
1757
|
end
|
1758
1758
|
end
|
1759
1759
|
|
1760
|
-
describe "#any?" do
|
1761
|
-
|
1762
|
-
let(:person) do
|
1763
|
-
Person.create!
|
1764
|
-
end
|
1765
|
-
|
1766
|
-
context "when nothing exists on the relation" do
|
1767
|
-
|
1768
|
-
context "when no document is added" do
|
1769
|
-
|
1770
|
-
let!(:sandwich) do
|
1771
|
-
Sandwich.create!
|
1772
|
-
end
|
1773
|
-
|
1774
|
-
it "returns false" do
|
1775
|
-
expect(sandwich.meats.any?).to be false
|
1776
|
-
end
|
1777
|
-
end
|
1778
|
-
|
1779
|
-
context "when the document is destroyed" do
|
1780
|
-
|
1781
|
-
before do
|
1782
|
-
Meat.create!
|
1783
|
-
end
|
1784
|
-
|
1785
|
-
let!(:sandwich) do
|
1786
|
-
Sandwich.create!
|
1787
|
-
end
|
1788
|
-
|
1789
|
-
it "returns false" do
|
1790
|
-
sandwich.destroy
|
1791
|
-
expect(sandwich.meats.any?).to be false
|
1792
|
-
end
|
1793
|
-
end
|
1794
|
-
end
|
1795
|
-
end
|
1796
|
-
|
1797
1760
|
context "when documents have been persisted" do
|
1798
1761
|
|
1799
1762
|
let!(:preference) do
|
@@ -3063,6 +3026,34 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
|
|
3063
3026
|
end
|
3064
3027
|
end
|
3065
3028
|
|
3029
|
+
# MONGOID-5844
|
3030
|
+
#
|
3031
|
+
# Specifically, this tests the case where the association is
|
3032
|
+
# initialized with a single element (so that Proxy#push does not take
|
3033
|
+
# the `concat` route), which causes `reset_unloaded` to be called, which
|
3034
|
+
# sets the `_unloaded` Criteria object to match only the specific element
|
3035
|
+
# that was given.
|
3036
|
+
#
|
3037
|
+
# The issue now is that when the events list is updated to be both events,
|
3038
|
+
# _unloaded matches one of them already, and the other has previously been
|
3039
|
+
# persisted so `new_record?` won't match it. We need to make sure the
|
3040
|
+
# `#size` logic properly accounts for this case.
|
3041
|
+
context 'when documents have been previously persisted' do
|
3042
|
+
let(:person1) { Person.create! }
|
3043
|
+
let(:person2) { Person.create! }
|
3044
|
+
let(:event1) { Event.create!(administrators: [ person1 ]) }
|
3045
|
+
let(:event2) { Event.create!(administrators: [ person2 ]) }
|
3046
|
+
|
3047
|
+
before do
|
3048
|
+
person1.administrated_events = [ event1, event2 ]
|
3049
|
+
end
|
3050
|
+
|
3051
|
+
it 'returns the number of associated documents [MONGOID-5844]' do
|
3052
|
+
expect(person1.administrated_events.to_a.size).to eq(2)
|
3053
|
+
expect(person1.administrated_events.size).to eq(2)
|
3054
|
+
end
|
3055
|
+
end
|
3056
|
+
|
3066
3057
|
context "when documents have not been persisted" do
|
3067
3058
|
|
3068
3059
|
before do
|