mongoid 8.1.3 → 8.1.11
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 +43 -45
- data/lib/mongoid/association/accessors.rb +5 -1
- data/lib/mongoid/association/eager_loadable.rb +3 -0
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +18 -3
- data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +21 -4
- data/lib/mongoid/association/referenced/has_many/proxy.rb +11 -2
- data/lib/mongoid/atomic.rb +9 -7
- data/lib/mongoid/attributes/readonly.rb +8 -3
- data/lib/mongoid/contextual/mongo.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -1
- data/lib/mongoid/criteria/queryable/selectable.rb +1 -1
- data/lib/mongoid/document.rb +8 -1
- data/lib/mongoid/equality.rb +1 -0
- data/lib/mongoid/extensions/hash.rb +4 -4
- data/lib/mongoid/fields.rb +13 -8
- data/lib/mongoid/interceptable.rb +6 -7
- data/lib/mongoid/matcher.rb +15 -1
- data/lib/mongoid/serializable.rb +7 -7
- data/lib/mongoid/timestamps/created.rb +8 -1
- data/lib/mongoid/touchable.rb +1 -1
- data/lib/mongoid/traversable.rb +36 -1
- data/lib/mongoid/validatable/associated.rb +98 -17
- data/lib/mongoid/validatable/macros.rb +15 -0
- data/lib/mongoid/validatable/numericality.rb +19 -0
- data/lib/mongoid/validatable.rb +9 -0
- data/lib/mongoid/version.rb +5 -1
- data/spec/integration/app_spec.rb +24 -5
- data/spec/integration/associations/embeds_one_spec.rb +25 -5
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +40 -0
- data/spec/mongoid/association/eager_spec.rb +24 -2
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +35 -0
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +4 -0
- data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +4 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +28 -37
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +42 -0
- data/spec/mongoid/attributes/readonly_spec.rb +19 -0
- data/spec/mongoid/attributes_spec.rb +16 -0
- data/spec/mongoid/contextual/mongo_spec.rb +78 -3
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +29 -0
- data/spec/mongoid/document_spec.rb +27 -0
- data/spec/mongoid/equality_spec.rb +6 -0
- data/spec/mongoid/fields_spec.rb +3 -3
- data/spec/mongoid/interceptable_spec.rb +80 -0
- data/spec/mongoid/interceptable_spec_models.rb +47 -111
- data/spec/mongoid/serializable_spec.rb +16 -9
- data/spec/mongoid/timestamps/created_spec.rb +23 -0
- data/spec/mongoid/validatable/associated_spec.rb +27 -34
- data/spec/mongoid/validatable/numericality_spec.rb +16 -0
- data/spec/shared/lib/mrss/docker_runner.rb +1 -2
- data/spec/shared/lib/mrss/release/candidate.rb +281 -0
- data/spec/shared/lib/mrss/release/product_data.rb +144 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +1 -1
- data/spec/shared/lib/tasks/candidate.rake +64 -0
- data/spec/shared/share/Dockerfile.erb +15 -85
- data/spec/shared/shlib/distro.sh +10 -0
- data/spec/shared/shlib/server.sh +33 -26
- data/spec/shared/shlib/set_env.sh +9 -68
- data/spec/support/expectations.rb +20 -17
- data/spec/support/models/band.rb +1 -0
- data/spec/support/models/lat_lng.rb +6 -0
- data/spec/support/models/name.rb +10 -0
- metadata +15 -38
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
|
@@ -15,32 +15,113 @@ 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
|
+
#
|
|
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? && (!value.persisted? || value.changed?)
|
|
77
|
+
value.validated? ? true : value.valid?
|
|
36
78
|
else
|
|
37
|
-
|
|
79
|
+
true
|
|
38
80
|
end
|
|
39
81
|
end.all?
|
|
40
|
-
ensure
|
|
41
|
-
document.exit_validate
|
|
42
82
|
end
|
|
43
|
-
|
|
83
|
+
|
|
84
|
+
document.errors.add(attribute, :invalid) unless valid
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
# Examine the given target object and return an array of
|
|
90
|
+
# documents (possibly empty) that the target represents.
|
|
91
|
+
#
|
|
92
|
+
# @param [ Array | Mongoid::Document | Mongoid::Association::Proxy | HasMany::Enumerable ] target
|
|
93
|
+
# the target object to examine.
|
|
94
|
+
#
|
|
95
|
+
# @return [ Array<Mongoid::Document> ] the list of documents
|
|
96
|
+
def get_target_documents(target)
|
|
97
|
+
if target.respond_to?(:_loaded?)
|
|
98
|
+
get_target_documents_for_has_many(target)
|
|
99
|
+
else
|
|
100
|
+
get_target_documents_for_other(target)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Returns the list of all currently in-memory values held by
|
|
105
|
+
# the target. The target will not be loaded.
|
|
106
|
+
#
|
|
107
|
+
# @param [ HasMany::Enumerable ] target the target that will
|
|
108
|
+
# be examined for in-memory documents.
|
|
109
|
+
#
|
|
110
|
+
# @return [ Array<Mongoid::Document> ] the in-memory documents
|
|
111
|
+
# held by the target.
|
|
112
|
+
def get_target_documents_for_has_many(target)
|
|
113
|
+
[ *target._loaded.values, *target._added.values ]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Returns the target as an array. If the target represents a single
|
|
117
|
+
# value, it is wrapped in an array.
|
|
118
|
+
#
|
|
119
|
+
# @param [ Array | Mongoid::Document | Mongoid::Association::Proxy ] target
|
|
120
|
+
# the target to return.
|
|
121
|
+
#
|
|
122
|
+
# @return [ Array<Mongoid::Document> ] the target, as an array.
|
|
123
|
+
def get_target_documents_for_other(target)
|
|
124
|
+
Array.wrap(target)
|
|
44
125
|
end
|
|
45
126
|
end
|
|
46
127
|
end
|
|
@@ -84,6 +84,21 @@ module Mongoid
|
|
|
84
84
|
def validates_presence_of(*args)
|
|
85
85
|
validates_with(PresenceValidator, _merge_attributes(args))
|
|
86
86
|
end
|
|
87
|
+
|
|
88
|
+
# Validates whether or not a field contains a numeric value.
|
|
89
|
+
#
|
|
90
|
+
# @example
|
|
91
|
+
# class Person
|
|
92
|
+
# include Mongoid::Document
|
|
93
|
+
# field :cost
|
|
94
|
+
#
|
|
95
|
+
# validates_numericality_of :cost
|
|
96
|
+
# end
|
|
97
|
+
#
|
|
98
|
+
# @param [ Object... ] *args The names of the field(s) to validate.
|
|
99
|
+
def validates_numericality_of(*args)
|
|
100
|
+
validates_with(NumericalityValidator, _merge_attributes(args))
|
|
101
|
+
end
|
|
87
102
|
end
|
|
88
103
|
end
|
|
89
104
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Validatable
|
|
5
|
+
# A specialization of the ActiveModel numericality validator, which adds
|
|
6
|
+
# logic to recognize and accept BSON::Decimal128 as a number.
|
|
7
|
+
class NumericalityValidator < ActiveModel::Validations::NumericalityValidator
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
# Ensure that BSON::Decimal128 is treated as a BigDecimal during the
|
|
11
|
+
# validation step.
|
|
12
|
+
def prepare_value_for_validation(value, record, attr_name)
|
|
13
|
+
result = super
|
|
14
|
+
|
|
15
|
+
result.is_a?(BSON::Decimal128) ? result.to_big_decimal : result
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/mongoid/validatable.rb
CHANGED
|
@@ -5,6 +5,7 @@ require "mongoid/validatable/localizable"
|
|
|
5
5
|
require "mongoid/validatable/associated"
|
|
6
6
|
require "mongoid/validatable/format"
|
|
7
7
|
require "mongoid/validatable/length"
|
|
8
|
+
require "mongoid/validatable/numericality"
|
|
8
9
|
require "mongoid/validatable/queryable"
|
|
9
10
|
require "mongoid/validatable/presence"
|
|
10
11
|
require "mongoid/validatable/uniqueness"
|
|
@@ -37,6 +38,14 @@ module Mongoid
|
|
|
37
38
|
Threaded.exit_validate(self)
|
|
38
39
|
end
|
|
39
40
|
|
|
41
|
+
# Perform a validation within the associated block.
|
|
42
|
+
def validating
|
|
43
|
+
begin_validate
|
|
44
|
+
yield
|
|
45
|
+
ensure
|
|
46
|
+
exit_validate
|
|
47
|
+
end
|
|
48
|
+
|
|
40
49
|
# Given the provided options, are we performing validations?
|
|
41
50
|
#
|
|
42
51
|
# @example Are we performing validations?
|
data/lib/mongoid/version.rb
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Mongoid
|
|
4
|
-
|
|
4
|
+
# The current version of Mongoid
|
|
5
|
+
#
|
|
6
|
+
# Note that this file is automatically updated via `rake candidate:create`.
|
|
7
|
+
# Manual changes to this file will be overwritten by that rake task.
|
|
8
|
+
VERSION = '8.1.11'
|
|
5
9
|
end
|
|
@@ -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'
|
|
@@ -26,6 +30,8 @@ describe 'Mongoid application tests' do
|
|
|
26
30
|
context 'demo application' do
|
|
27
31
|
context 'sinatra' do
|
|
28
32
|
it 'runs' do
|
|
33
|
+
skip 'https://jira.mongodb.org/browse/MONGOID-5826'
|
|
34
|
+
|
|
29
35
|
clone_application(
|
|
30
36
|
'https://github.com/mongoid/mongoid-demo',
|
|
31
37
|
subdir: 'sinatra-minimal',
|
|
@@ -45,6 +51,8 @@ describe 'Mongoid application tests' do
|
|
|
45
51
|
|
|
46
52
|
context 'rails-api' do
|
|
47
53
|
it 'runs' do
|
|
54
|
+
skip 'https://jira.mongodb.org/browse/MONGOID-5826'
|
|
55
|
+
|
|
48
56
|
clone_application(
|
|
49
57
|
'https://github.com/mongoid/mongoid-demo',
|
|
50
58
|
subdir: 'rails-api',
|
|
@@ -87,6 +95,12 @@ describe 'Mongoid application tests' do
|
|
|
87
95
|
end
|
|
88
96
|
|
|
89
97
|
context 'new application - rails' do
|
|
98
|
+
before(:all) do
|
|
99
|
+
if SpecConfig.instance.rails_version < '7.1'
|
|
100
|
+
skip '`rails new` with rails < 7.1 fails because modern concurrent-ruby removed logger dependency'
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
90
104
|
it 'creates' do
|
|
91
105
|
install_rails
|
|
92
106
|
|
|
@@ -95,7 +109,7 @@ describe 'Mongoid application tests' do
|
|
|
95
109
|
check_call(%w(rails new mongoid-test --skip-spring --skip-active-record), env: clean_env)
|
|
96
110
|
|
|
97
111
|
Dir.chdir('mongoid-test') do
|
|
98
|
-
adjust_app_gemfile
|
|
112
|
+
adjust_app_gemfile(add_sprockets: SpecConfig.instance.rails_version != '8.0')
|
|
99
113
|
check_call(%w(bundle install), env: clean_env)
|
|
100
114
|
|
|
101
115
|
check_call(%w(rails g model post), env: clean_env)
|
|
@@ -117,7 +131,7 @@ describe 'Mongoid application tests' do
|
|
|
117
131
|
check_call(%w(rails new mongoid-test-config --skip-spring --skip-active-record), env: clean_env)
|
|
118
132
|
|
|
119
133
|
Dir.chdir('mongoid-test-config') do
|
|
120
|
-
adjust_app_gemfile
|
|
134
|
+
adjust_app_gemfile(add_sprockets: SpecConfig.instance.rails_version != '8.0')
|
|
121
135
|
check_call(%w(bundle install), env: clean_env)
|
|
122
136
|
|
|
123
137
|
mongoid_config_file = File.join(TMP_BASE,'mongoid-test-config/config/mongoid.yml')
|
|
@@ -139,7 +153,7 @@ describe 'Mongoid application tests' do
|
|
|
139
153
|
if (rails_version = SpecConfig.instance.rails_version) == 'master'
|
|
140
154
|
else
|
|
141
155
|
check_call(%w(gem list))
|
|
142
|
-
check_call(%w(gem install rails --no-document -v) + ["~> #{rails_version}.0"])
|
|
156
|
+
check_call(%w(gem install rails --no-document --force -v) + ["~> #{rails_version}.0"])
|
|
143
157
|
end
|
|
144
158
|
end
|
|
145
159
|
|
|
@@ -205,7 +219,7 @@ describe 'Mongoid application tests' do
|
|
|
205
219
|
FileUtils.rm_rf(File.basename(repo_url))
|
|
206
220
|
check_call(%w(git clone) + [repo_url])
|
|
207
221
|
Dir.chdir(File.join(*[File.basename(repo_url), subdir].compact)) do
|
|
208
|
-
adjust_app_gemfile
|
|
222
|
+
adjust_app_gemfile(add_sprockets: false)
|
|
209
223
|
adjust_rails_defaults
|
|
210
224
|
check_call(%w(bundle install), env: clean_env)
|
|
211
225
|
puts `git diff`
|
|
@@ -262,7 +276,7 @@ describe 'Mongoid application tests' do
|
|
|
262
276
|
end
|
|
263
277
|
end
|
|
264
278
|
|
|
265
|
-
def adjust_app_gemfile(rails_version: SpecConfig.instance.rails_version)
|
|
279
|
+
def adjust_app_gemfile(rails_version: SpecConfig.instance.rails_version, add_sprockets: true)
|
|
266
280
|
remove_bundler_req
|
|
267
281
|
|
|
268
282
|
gemfile_lines = IO.readlines('Gemfile')
|
|
@@ -280,12 +294,17 @@ describe 'Mongoid application tests' do
|
|
|
280
294
|
gemfile_lines << "gem 'rails', '~> #{rails_version}.0'\n"
|
|
281
295
|
end
|
|
282
296
|
end
|
|
297
|
+
gemfile_lines << "gem 'sprockets-rails'\n" if add_sprockets
|
|
283
298
|
File.open('Gemfile', 'w') do |f|
|
|
284
299
|
f << gemfile_lines.join
|
|
285
300
|
end
|
|
286
301
|
end
|
|
287
302
|
|
|
288
303
|
def adjust_rails_defaults(rails_version: SpecConfig.instance.rails_version)
|
|
304
|
+
if !rails_version.match?(/^\d+\.\d+$/)
|
|
305
|
+
# This must be pre-release version, we trim it
|
|
306
|
+
rails_version = rails_version.split('.')[0..1].join('.')
|
|
307
|
+
end
|
|
289
308
|
if File.exist?('config/application.rb')
|
|
290
309
|
lines = IO.readlines('config/application.rb')
|
|
291
310
|
lines.each do |line|
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
5
|
describe 'embeds_one associations' do
|
|
6
|
-
|
|
7
|
-
context 're-associating the same object' do
|
|
6
|
+
context 'when re-associating the same object' do
|
|
8
7
|
context 'with dependent: destroy' do
|
|
9
8
|
let(:canvas) do
|
|
10
9
|
Canvas.create!(palette: Palette.new)
|
|
@@ -16,7 +15,7 @@ describe 'embeds_one associations' do
|
|
|
16
15
|
canvas.palette = canvas.palette
|
|
17
16
|
canvas.save!
|
|
18
17
|
canvas.reload
|
|
19
|
-
canvas.palette.
|
|
18
|
+
expect(canvas.palette).to eq palette
|
|
20
19
|
end
|
|
21
20
|
end
|
|
22
21
|
end
|
|
@@ -30,12 +29,33 @@ describe 'embeds_one associations' do
|
|
|
30
29
|
end
|
|
31
30
|
|
|
32
31
|
it 'loads the association correctly' do
|
|
33
|
-
expect { klass }.
|
|
34
|
-
expect { klass.new.address }.
|
|
32
|
+
expect { klass }.not_to raise_error
|
|
33
|
+
expect { klass.new.address }.not_to raise_error
|
|
35
34
|
instance = klass.new
|
|
36
35
|
address = Address.new
|
|
37
36
|
instance.address = address
|
|
38
37
|
expect(instance.address).to eq address
|
|
39
38
|
end
|
|
40
39
|
end
|
|
40
|
+
|
|
41
|
+
context 'when parent is persisted' do
|
|
42
|
+
let!(:person) do
|
|
43
|
+
Person.create!
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context 'when assigning the new child' do
|
|
47
|
+
context 'when assigning an attribute to the child' do
|
|
48
|
+
before do
|
|
49
|
+
# person.reload
|
|
50
|
+
person.name = Name.new
|
|
51
|
+
person.name.first_name = 'Dmitry'
|
|
52
|
+
person.save!
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'persists the child' do
|
|
56
|
+
expect(person.reload.name.first_name).to eq 'Dmitry'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
41
61
|
end
|
|
@@ -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
|
|
@@ -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
|
|
|
@@ -2310,9 +2310,37 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
|
|
|
2310
2310
|
person.addresses.create!(street: "Bond St")
|
|
2311
2311
|
end
|
|
2312
2312
|
|
|
2313
|
+
let(:address) { person.addresses.first }
|
|
2314
|
+
|
|
2313
2315
|
it "returns true" do
|
|
2314
2316
|
expect(person.addresses.exists?).to be true
|
|
2315
2317
|
end
|
|
2318
|
+
|
|
2319
|
+
context 'when given specifying conditions' do
|
|
2320
|
+
context 'when the record exists in the association' do
|
|
2321
|
+
it 'returns true by condition' do
|
|
2322
|
+
expect(person.addresses.exists?(street: 'Bond St')).to be true
|
|
2323
|
+
end
|
|
2324
|
+
|
|
2325
|
+
it 'returns true by id' do
|
|
2326
|
+
expect(person.addresses.exists?(address._id)).to be true
|
|
2327
|
+
end
|
|
2328
|
+
|
|
2329
|
+
it 'returns false when given false' do
|
|
2330
|
+
expect(person.addresses.exists?(false)).to be false
|
|
2331
|
+
end
|
|
2332
|
+
|
|
2333
|
+
it 'returns false when given nil' do
|
|
2334
|
+
expect(person.addresses.exists?(nil)).to be false
|
|
2335
|
+
end
|
|
2336
|
+
end
|
|
2337
|
+
|
|
2338
|
+
context 'when the record does not exist in the association' do
|
|
2339
|
+
it 'returns false' do
|
|
2340
|
+
expect(person.addresses.exists?(street: 'Garfield Ave')).to be false
|
|
2341
|
+
end
|
|
2342
|
+
end
|
|
2343
|
+
end
|
|
2316
2344
|
end
|
|
2317
2345
|
|
|
2318
2346
|
context "when no documents exist in the database" do
|
|
@@ -2324,6 +2352,13 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
|
|
|
2324
2352
|
it "returns false" do
|
|
2325
2353
|
expect(person.addresses.exists?).to be false
|
|
2326
2354
|
end
|
|
2355
|
+
|
|
2356
|
+
context 'when given specifying conditions' do
|
|
2357
|
+
it 'returns false' do
|
|
2358
|
+
expect(person.addresses.exists?(street: 'Hyde Park Dr')).to be false
|
|
2359
|
+
expect(person.addresses.exists?(street: 'Garfield Ave')).to be false
|
|
2360
|
+
end
|
|
2361
|
+
end
|
|
2327
2362
|
end
|
|
2328
2363
|
end
|
|
2329
2364
|
|
|
@@ -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
|
|
@@ -749,6 +749,10 @@ describe Mongoid::Association::Referenced::BelongsTo::Proxy do
|
|
|
749
749
|
person.save!
|
|
750
750
|
end
|
|
751
751
|
|
|
752
|
+
# NOTE: there as a bad interdependency here, with the auto_save_spec.rb
|
|
753
|
+
# file. If auto_save_spec.rb runs before this, the following specs fail
|
|
754
|
+
# with "undefined method `nullify' for an instance of Person".
|
|
755
|
+
|
|
752
756
|
context "when parent exists" do
|
|
753
757
|
|
|
754
758
|
context "when child is destroyed" do
|
|
@@ -1755,43 +1755,6 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
|
|
|
1755
1755
|
end
|
|
1756
1756
|
end
|
|
1757
1757
|
|
|
1758
|
-
describe "#any?" do
|
|
1759
|
-
|
|
1760
|
-
let(:person) do
|
|
1761
|
-
Person.create!
|
|
1762
|
-
end
|
|
1763
|
-
|
|
1764
|
-
context "when nothing exists on the relation" do
|
|
1765
|
-
|
|
1766
|
-
context "when no document is added" do
|
|
1767
|
-
|
|
1768
|
-
let!(:sandwich) do
|
|
1769
|
-
Sandwich.create!
|
|
1770
|
-
end
|
|
1771
|
-
|
|
1772
|
-
it "returns false" do
|
|
1773
|
-
expect(sandwich.meats.any?).to be false
|
|
1774
|
-
end
|
|
1775
|
-
end
|
|
1776
|
-
|
|
1777
|
-
context "when the document is destroyed" do
|
|
1778
|
-
|
|
1779
|
-
before do
|
|
1780
|
-
Meat.create!
|
|
1781
|
-
end
|
|
1782
|
-
|
|
1783
|
-
let!(:sandwich) do
|
|
1784
|
-
Sandwich.create!
|
|
1785
|
-
end
|
|
1786
|
-
|
|
1787
|
-
it "returns false" do
|
|
1788
|
-
sandwich.destroy
|
|
1789
|
-
expect(sandwich.meats.any?).to be false
|
|
1790
|
-
end
|
|
1791
|
-
end
|
|
1792
|
-
end
|
|
1793
|
-
end
|
|
1794
|
-
|
|
1795
1758
|
context "when documents have been persisted" do
|
|
1796
1759
|
|
|
1797
1760
|
let!(:preference) do
|
|
@@ -3041,6 +3004,34 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
|
|
|
3041
3004
|
end
|
|
3042
3005
|
end
|
|
3043
3006
|
|
|
3007
|
+
# MONGOID-5844
|
|
3008
|
+
#
|
|
3009
|
+
# Specifically, this tests the case where the association is
|
|
3010
|
+
# initialized with a single element (so that Proxy#push does not take
|
|
3011
|
+
# the `concat` route), which causes `reset_unloaded` to be called, which
|
|
3012
|
+
# sets the `_unloaded` Criteria object to match only the specific element
|
|
3013
|
+
# that was given.
|
|
3014
|
+
#
|
|
3015
|
+
# The issue now is that when the events list is updated to be both events,
|
|
3016
|
+
# _unloaded matches one of them already, and the other has previously been
|
|
3017
|
+
# persisted so `new_record?` won't match it. We need to make sure the
|
|
3018
|
+
# `#size` logic properly accounts for this case.
|
|
3019
|
+
context 'when documents have been previously persisted' do
|
|
3020
|
+
let(:person1) { Person.create! }
|
|
3021
|
+
let(:person2) { Person.create! }
|
|
3022
|
+
let(:event1) { Event.create!(administrators: [ person1 ]) }
|
|
3023
|
+
let(:event2) { Event.create!(administrators: [ person2 ]) }
|
|
3024
|
+
|
|
3025
|
+
before do
|
|
3026
|
+
person1.administrated_events = [ event1, event2 ]
|
|
3027
|
+
end
|
|
3028
|
+
|
|
3029
|
+
it 'returns the number of associated documents [MONGOID-5844]' do
|
|
3030
|
+
expect(person1.administrated_events.to_a.size).to eq(2)
|
|
3031
|
+
expect(person1.administrated_events.size).to eq(2)
|
|
3032
|
+
end
|
|
3033
|
+
end
|
|
3034
|
+
|
|
3044
3035
|
context "when documents have not been persisted" do
|
|
3045
3036
|
|
|
3046
3037
|
before do
|
|
@@ -2395,6 +2395,42 @@ describe Mongoid::Association::Referenced::HasMany::Proxy do
|
|
|
2395
2395
|
end
|
|
2396
2396
|
end
|
|
2397
2397
|
end
|
|
2398
|
+
|
|
2399
|
+
context 'when invoked with specifying conditions' do
|
|
2400
|
+
let(:other_person) { Person.create! }
|
|
2401
|
+
let(:post) { person.posts.first }
|
|
2402
|
+
|
|
2403
|
+
before do
|
|
2404
|
+
person.posts.create title: 'bumfuzzle'
|
|
2405
|
+
other_person.posts.create title: 'bumbershoot'
|
|
2406
|
+
end
|
|
2407
|
+
|
|
2408
|
+
context 'when the conditions match an associated record' do
|
|
2409
|
+
it 'detects its existence by condition' do
|
|
2410
|
+
expect(person.posts.exists?(title: 'bumfuzzle')).to be true
|
|
2411
|
+
expect(other_person.posts.exists?(title: 'bumbershoot')).to be true
|
|
2412
|
+
end
|
|
2413
|
+
|
|
2414
|
+
it 'detects its existence by id' do
|
|
2415
|
+
expect(person.posts.exists?(post._id)).to be true
|
|
2416
|
+
end
|
|
2417
|
+
|
|
2418
|
+
it 'returns false when given false' do
|
|
2419
|
+
expect(person.posts.exists?(false)).to be false
|
|
2420
|
+
end
|
|
2421
|
+
|
|
2422
|
+
it 'returns false when given nil' do
|
|
2423
|
+
expect(person.posts.exists?(nil)).to be false
|
|
2424
|
+
end
|
|
2425
|
+
end
|
|
2426
|
+
|
|
2427
|
+
context 'when the conditions match an unassociated record' do
|
|
2428
|
+
it 'does not detect its existence' do
|
|
2429
|
+
expect(person.posts.exists?(title: 'bumbershoot')).to be false
|
|
2430
|
+
expect(other_person.posts.exists?(title: 'bumfuzzle')).to be false
|
|
2431
|
+
end
|
|
2432
|
+
end
|
|
2433
|
+
end
|
|
2398
2434
|
end
|
|
2399
2435
|
|
|
2400
2436
|
context "when documents exist in application but not in database" do
|
|
@@ -2465,6 +2501,12 @@ describe Mongoid::Association::Referenced::HasMany::Proxy do
|
|
|
2465
2501
|
end
|
|
2466
2502
|
end
|
|
2467
2503
|
end
|
|
2504
|
+
|
|
2505
|
+
context 'when invoked with specifying conditions' do
|
|
2506
|
+
it 'returns false' do
|
|
2507
|
+
expect(person.posts.exists?(title: 'hullaballoo')).to be false
|
|
2508
|
+
end
|
|
2509
|
+
end
|
|
2468
2510
|
end
|
|
2469
2511
|
end
|
|
2470
2512
|
|