mongoid 9.1.0 → 9.1.2
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 +69 -0
- data/lib/mongoid/association/accessors.rb +27 -5
- data/lib/mongoid/association/depending.rb +14 -10
- data/lib/mongoid/association/eager.rb +9 -0
- data/lib/mongoid/association/eager_load/discriminated_inclusion.rb +88 -0
- data/lib/mongoid/association/eager_load/embedded_distributor.rb +151 -0
- data/lib/mongoid/association/eager_load/inclusion.rb +173 -0
- data/lib/mongoid/association/eager_load/inclusion_tree.rb +96 -0
- data/lib/mongoid/association/eager_load/lookup_pipeline.rb +121 -0
- data/lib/mongoid/association/eager_load/polymorphic_preloader.rb +61 -0
- data/lib/mongoid/association/eager_load/polymorphic_targets.rb +151 -0
- data/lib/mongoid/association/eager_loadable.rb +65 -101
- data/lib/mongoid/association/embedded/batchable.rb +17 -1
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +6 -1
- data/lib/mongoid/association/embedded/embeds_one.rb +1 -0
- data/lib/mongoid/association/macros.rb +13 -1
- data/lib/mongoid/association/nested/many.rb +34 -5
- data/lib/mongoid/association/nested/nested_buildable.rb +14 -0
- data/lib/mongoid/association/nested/one.rb +6 -1
- data/lib/mongoid/association/options.rb +17 -0
- data/lib/mongoid/association/referenced/belongs_to/eager.rb +6 -1
- data/lib/mongoid/association/referenced/belongs_to.rb +1 -0
- data/lib/mongoid/association/referenced/counter_cache.rb +3 -3
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +6 -0
- data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +5 -0
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +3 -1
- data/lib/mongoid/association/referenced/has_many/proxy.rb +100 -1
- data/lib/mongoid/association/referenced/has_many_through/eager.rb +99 -0
- data/lib/mongoid/association/referenced/has_many_through/proxy.rb +68 -0
- data/lib/mongoid/association/referenced/has_many_through.rb +201 -0
- data/lib/mongoid/association/referenced/has_one.rb +1 -0
- data/lib/mongoid/association/referenced/has_one_through/eager.rb +65 -0
- data/lib/mongoid/association/referenced/has_one_through/proxy.rb +30 -0
- data/lib/mongoid/association/referenced/has_one_through.rb +167 -0
- data/lib/mongoid/association/referenced.rb +2 -0
- data/lib/mongoid/association/relatable.rb +58 -0
- data/lib/mongoid/association.rb +15 -0
- data/lib/mongoid/atomic/modifiers.rb +100 -16
- data/lib/mongoid/clients/factory.rb +9 -13
- data/lib/mongoid/collection_configurable.rb +8 -0
- data/lib/mongoid/config/defaults.rb +0 -1
- data/lib/mongoid/config/encryption.rb +170 -22
- data/lib/mongoid/config.rb +56 -5
- data/lib/mongoid/contextual/aggregable/memory.rb +6 -2
- data/lib/mongoid/contextual/memory.rb +18 -7
- data/lib/mongoid/criteria/includable.rb +35 -11
- data/lib/mongoid/criteria/queryable/mergeable.rb +4 -0
- data/lib/mongoid/criteria/queryable/selectable.rb +123 -7
- data/lib/mongoid/deprecable.rb +45 -2
- data/lib/mongoid/document.rb +3 -0
- data/lib/mongoid/encryptable.rb +73 -0
- data/lib/mongoid/errors/config_redactor.rb +43 -0
- data/lib/mongoid/errors/in_memory_regexp_timeout.rb +26 -0
- data/lib/mongoid/errors/invalid_encryption_schema.rb +27 -0
- data/lib/mongoid/errors/mixed_client_configuration.rb +1 -1
- data/lib/mongoid/errors/no_client_database.rb +1 -1
- data/lib/mongoid/errors/no_client_hosts.rb +1 -1
- data/lib/mongoid/errors/no_encryption_schema.rb +30 -0
- data/lib/mongoid/errors/readonly_association.rb +29 -0
- data/lib/mongoid/errors.rb +5 -0
- data/lib/mongoid/extensions/vector.rb +64 -0
- data/lib/mongoid/extensions.rb +1 -0
- data/lib/mongoid/field_readable.rb +69 -0
- data/lib/mongoid/fields.rb +7 -0
- data/lib/mongoid/indexable.rb +38 -26
- data/lib/mongoid/matchable.rb +6 -1
- data/lib/mongoid/matcher/eq_impl_with_regexp.rb +2 -4
- data/lib/mongoid/matcher/regex.rb +11 -12
- data/lib/mongoid/matcher/regexp_budget.rb +372 -0
- data/lib/mongoid/matcher.rb +1 -0
- data/lib/mongoid/persistable/creatable.rb +120 -14
- data/lib/mongoid/persistable/updatable.rb +9 -11
- data/lib/mongoid/persistable.rb +15 -15
- data/lib/mongoid/persistence_context.rb +77 -0
- data/lib/mongoid/search_indexable.rb +69 -24
- data/lib/mongoid/serializable.rb +12 -4
- data/lib/mongoid/tasks/database.rb +33 -16
- data/lib/mongoid/threaded.rb +36 -0
- data/lib/mongoid/timestamps/timeless.rb +84 -10
- data/lib/mongoid/touchable.rb +28 -1
- data/lib/mongoid/traversable.rb +2 -2
- data/lib/mongoid/validatable/associated.rb +18 -2
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/warnings.rb +4 -0
- data/spec/integration/app_spec.rb +7 -1
- data/spec/integration/associations/belongs_to_spec.rb +13 -0
- data/spec/integration/associations/embedded_delayed_atomic_sets_spec.rb +216 -0
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +31 -2
- data/spec/integration/atomic/modifiers_spec.rb +283 -0
- data/spec/integration/dots_and_dollars_spec.rb +12 -2
- data/spec/integration/encryption_spec.rb +300 -0
- data/spec/integration/matcher_operator_data/regex.yml +21 -0
- data/spec/integration/matcher_regexp_timeout_spec.rb +215 -0
- data/spec/integration/query_operator_guard_spec.rb +89 -0
- data/spec/mongoid/association/accessors_spec.rb +35 -0
- data/spec/mongoid/association/eager_loadable_spec.rb +47 -0
- data/spec/mongoid/association/eager_spec.rb +2 -2
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +33 -0
- data/spec/mongoid/association/fallback_spec.rb +425 -0
- data/spec/mongoid/association/macros_spec.rb +26 -0
- data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +17 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +11 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +48 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +50 -0
- data/spec/mongoid/association/referenced/has_many/eager_spec.rb +33 -0
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +145 -0
- data/spec/mongoid/association/referenced/has_many_through/eager_spec.rb +58 -0
- data/spec/mongoid/association/referenced/has_many_through/proxy_spec.rb +62 -0
- data/spec/mongoid/association/referenced/has_many_through_spec.rb +399 -0
- data/spec/mongoid/association/referenced/has_one_through/eager_spec.rb +58 -0
- data/spec/mongoid/association/referenced/has_one_through/proxy_spec.rb +49 -0
- data/spec/mongoid/association/referenced/has_one_through_spec.rb +211 -0
- data/spec/mongoid/atomic/modifiers_spec.rb +347 -0
- data/spec/mongoid/attributes/nested_spec.rb +278 -8
- data/spec/mongoid/clients/factory_spec.rb +36 -0
- data/spec/mongoid/config/defaults_spec.rb +33 -0
- data/spec/mongoid/config/encryption_spec.rb +451 -0
- data/spec/mongoid/contextual/aggregable/memory_spec.rb +91 -0
- data/spec/mongoid/contextual/memory_spec.rb +177 -0
- data/spec/mongoid/criteria/includable_spec.rb +1221 -0
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +15 -1
- data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +201 -0
- data/spec/mongoid/criteria_spec.rb +3 -0
- data/spec/mongoid/encryptable_spec.rb +115 -0
- data/spec/mongoid/errors/config_redactor_spec.rb +112 -0
- data/spec/mongoid/errors/mixed_client_configuration_spec.rb +31 -0
- data/spec/mongoid/errors/no_client_database_spec.rb +29 -0
- data/spec/mongoid/errors/no_client_hosts_spec.rb +26 -0
- data/spec/mongoid/errors/readonly_association_spec.rb +34 -0
- data/spec/mongoid/extensions/vector_spec.rb +175 -0
- data/spec/mongoid/fields_spec.rb +8 -0
- data/spec/mongoid/matcher/regexp_budget_spec.rb +570 -0
- data/spec/mongoid/search_indexable_spec.rb +321 -9
- data/spec/mongoid/tasks/database_spec.rb +31 -0
- data/spec/mongoid/timestamps/timeless_spec.rb +197 -5
- data/spec/mongoid/touchable_spec.rb +242 -0
- data/spec/mongoid/touchable_spec_models.rb +47 -0
- data/spec/mongoid/validatable/associated_spec.rb +19 -0
- data/spec/spec_helper.rb +5 -1
- data/spec/support/crypt/models.rb +253 -0
- data/spec/support/models/modifier_models.rb +65 -0
- metadata +55 -2
|
@@ -7,6 +7,33 @@ require_relative '../association/referenced/has_and_belongs_to_many_models'
|
|
|
7
7
|
require_relative 'nested_spec_models'
|
|
8
8
|
|
|
9
9
|
describe Mongoid::Attributes::Nested do
|
|
10
|
+
# Expects the enclosing context to define `build_with_id`, taking an id
|
|
11
|
+
# value and returning the document built with it in nested attributes.
|
|
12
|
+
shared_examples 'rejects non-scalar ids' do |klass_name|
|
|
13
|
+
not_found = /not found for class #{klass_name}/
|
|
14
|
+
|
|
15
|
+
context 'when the id is an operator hash' do
|
|
16
|
+
it 'raises a document not found error' do
|
|
17
|
+
expect { build_with_id({ '$ne' => nil }) }
|
|
18
|
+
.to raise_error(Mongoid::Errors::DocumentNotFound, not_found)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context 'when the id is an array' do
|
|
23
|
+
it 'raises a document not found error' do
|
|
24
|
+
expect { build_with_id([ BSON::ObjectId.new ]) }
|
|
25
|
+
.to raise_error(Mongoid::Errors::DocumentNotFound, not_found)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'when the id is a malformed object id hash' do
|
|
30
|
+
it 'raises a document not found error' do
|
|
31
|
+
expect { build_with_id({ '$oid' => 'junk' }) }
|
|
32
|
+
.to raise_error(Mongoid::Errors::DocumentNotFound, not_found)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
10
37
|
describe '.accepts_nested_attributes_for' do
|
|
11
38
|
context 'when the autosave option is not defined' do
|
|
12
39
|
let(:person) do
|
|
@@ -188,10 +215,110 @@ describe Mongoid::Attributes::Nested do
|
|
|
188
215
|
it 'sets the nested attributes' do
|
|
189
216
|
expect(person2.posts.map(&:title)).to eq([ 'Reparented!' ])
|
|
190
217
|
end
|
|
218
|
+
|
|
219
|
+
context 'when the id does not correspond to an existing document' do
|
|
220
|
+
let(:person2) do
|
|
221
|
+
Person.create!(posts_attributes: { '0' => { id: BSON::ObjectId.new, title: 'Ghost' } })
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
context 'when raise_not_found_error is true' do
|
|
225
|
+
config_override :raise_not_found_error, true
|
|
226
|
+
|
|
227
|
+
it 'raises a document not found error' do
|
|
228
|
+
expect { person2 }.to raise_error(Mongoid::Errors::DocumentNotFound,
|
|
229
|
+
/Document\(s\) not found for class Post/)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
context 'when raise_not_found_error is false' do
|
|
234
|
+
config_override :raise_not_found_error, false
|
|
235
|
+
|
|
236
|
+
it 'raises a document not found error' do
|
|
237
|
+
expect { person2 }.to raise_error(Mongoid::Errors::DocumentNotFound,
|
|
238
|
+
/Document\(s\) not found for class Post/)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
context 'when _destroy is true for a document not in the relation' do
|
|
245
|
+
config_override :allow_reparenting_via_nested_attributes, true
|
|
246
|
+
|
|
247
|
+
before do
|
|
248
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
249
|
+
Person.accepts_nested_attributes_for :posts, allow_destroy: true
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
let(:person3) do
|
|
253
|
+
Person.create!(
|
|
254
|
+
posts_attributes: { '0' => { id: post.id, _destroy: '1' } }
|
|
255
|
+
)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
it 'does not raise UnknownAttribute' do
|
|
259
|
+
expect { person3 }.not_to raise_error
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it 'does not add the document to the relation' do
|
|
263
|
+
expect(person3.posts).to be_empty
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
context 'when the id in the attributes is not a scalar' do
|
|
269
|
+
let(:person) { Person.create! }
|
|
270
|
+
|
|
271
|
+
def build_with_id(id)
|
|
272
|
+
person.update!(posts_attributes: { '0' => { id: id, title: 'Crafted' } })
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
context 'when the association is empty' do
|
|
276
|
+
include_examples 'rejects non-scalar ids', 'Post'
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
context 'when the association is not empty' do
|
|
280
|
+
before { person.posts.create!(title: 'Existing') }
|
|
281
|
+
|
|
282
|
+
include_examples 'rejects non-scalar ids', 'Post'
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
context 'when allow_reparenting_via_nested_attributes is true' do
|
|
286
|
+
config_override :allow_reparenting_via_nested_attributes, true
|
|
287
|
+
|
|
288
|
+
include_examples 'rejects non-scalar ids', 'Post'
|
|
191
289
|
end
|
|
192
290
|
end
|
|
193
291
|
end
|
|
194
292
|
|
|
293
|
+
context 'when a has-many association uses a custom primary key' do
|
|
294
|
+
# A throwaway class, so that accepts_nested_attributes_for does not
|
|
295
|
+
# leave autosave callbacks and nested attributes on a shared model.
|
|
296
|
+
let(:company_class) do
|
|
297
|
+
stub_const('NestedSpecCompany', Class.new do
|
|
298
|
+
include Mongoid::Document
|
|
299
|
+
|
|
300
|
+
store_in collection: 'hmm_companies'
|
|
301
|
+
field :p, type: Integer
|
|
302
|
+
has_many :emails, primary_key: :p, foreign_key: :f, class_name: 'HmmEmail', inverse_of: nil
|
|
303
|
+
accepts_nested_attributes_for :emails
|
|
304
|
+
end)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
after do
|
|
308
|
+
Mongoid.deregister_model(company_class)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
it 'reports the parent primary key value in the error params' do
|
|
312
|
+
company = company_class.create!(p: 42)
|
|
313
|
+
|
|
314
|
+
expect do
|
|
315
|
+
company.emails_attributes = { '0' => { 'id' => 'missing', 'f' => 42 } }
|
|
316
|
+
end.to raise_error(Mongoid::Errors::DocumentNotFound) { |error|
|
|
317
|
+
expect(error.params).to eq({ _id: 'missing', 'f' => 42 })
|
|
318
|
+
}
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
195
322
|
context 'when the relation is a has-and-belongs-to-many' do
|
|
196
323
|
before do
|
|
197
324
|
Person.send(:undef_method, :preferences_attributes=)
|
|
@@ -214,16 +341,100 @@ describe Mongoid::Attributes::Nested do
|
|
|
214
341
|
)
|
|
215
342
|
end
|
|
216
343
|
|
|
217
|
-
|
|
218
|
-
|
|
344
|
+
context 'when allow_reparenting_via_nested_attributes is false' do
|
|
345
|
+
config_override :allow_reparenting_via_nested_attributes, false
|
|
346
|
+
|
|
347
|
+
it 'raises a document not found error' do
|
|
348
|
+
expect { person }.to raise_error(Mongoid::Errors::DocumentNotFound,
|
|
349
|
+
/Document\(s\) not found for class Preference/)
|
|
350
|
+
end
|
|
219
351
|
end
|
|
220
352
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
353
|
+
context 'when allow_reparenting_via_nested_attributes is true' do
|
|
354
|
+
config_override :allow_reparenting_via_nested_attributes, true
|
|
355
|
+
|
|
356
|
+
it 'sets the nested attributes' do
|
|
357
|
+
expect(person.preferences.map(&:name)).to eq([ preference.name ])
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
it 'updates attributes of existing document which is added to relation' do
|
|
361
|
+
preference_name = 'updated preference'
|
|
362
|
+
person = Person.new(
|
|
363
|
+
preferences_attributes: { 0 => { id: preference.id, name: preference_name } }
|
|
364
|
+
)
|
|
365
|
+
expect(person.preferences.map(&:name)).to eq([ preference_name ])
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
context 'when the id does not correspond to an existing document' do
|
|
369
|
+
let(:person) do
|
|
370
|
+
Person.new(
|
|
371
|
+
preferences_attributes: { 0 => { id: BSON::ObjectId.new, name: 'Ghost' } }
|
|
372
|
+
)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
context 'when raise_not_found_error is true' do
|
|
376
|
+
config_override :raise_not_found_error, true
|
|
377
|
+
|
|
378
|
+
it 'raises a document not found error' do
|
|
379
|
+
expect { person }.to raise_error(Mongoid::Errors::DocumentNotFound,
|
|
380
|
+
/Document\(s\) not found for class Preference/)
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
context 'when raise_not_found_error is false' do
|
|
385
|
+
config_override :raise_not_found_error, false
|
|
386
|
+
|
|
387
|
+
it 'raises a document not found error' do
|
|
388
|
+
expect { person }.to raise_error(Mongoid::Errors::DocumentNotFound,
|
|
389
|
+
/Document\(s\) not found for class Preference/)
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
context 'when _destroy is true for a document not in the relation' do
|
|
396
|
+
before do
|
|
397
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
398
|
+
Person.accepts_nested_attributes_for :preferences, allow_destroy: true
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
let(:person) do
|
|
402
|
+
Person.new(
|
|
403
|
+
preferences_attributes: { 0 => { id: preference.id, _destroy: '1' } }
|
|
404
|
+
)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
it 'does not raise UnknownAttribute' do
|
|
408
|
+
expect { person }.not_to raise_error
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
it 'does not add the document to the relation' do
|
|
412
|
+
expect(person.preferences).to be_empty
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
context 'when the id in the attributes is not a scalar' do
|
|
418
|
+
let(:target) { Person.create! }
|
|
419
|
+
|
|
420
|
+
def build_with_id(id)
|
|
421
|
+
target.update!(preferences_attributes: { 0 => { id: id, name: 'Crafted' } })
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
context 'when the association is empty' do
|
|
425
|
+
include_examples 'rejects non-scalar ids', 'Preference'
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
context 'when the association is not empty' do
|
|
429
|
+
before { target.preferences.create!(name: 'Existing') }
|
|
430
|
+
|
|
431
|
+
include_examples 'rejects non-scalar ids', 'Preference'
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
context 'when allow_reparenting_via_nested_attributes is true' do
|
|
435
|
+
config_override :allow_reparenting_via_nested_attributes, true
|
|
436
|
+
|
|
437
|
+
include_examples 'rejects non-scalar ids', 'Preference'
|
|
227
438
|
end
|
|
228
439
|
end
|
|
229
440
|
end
|
|
@@ -4552,4 +4763,63 @@ describe Mongoid::Attributes::Nested do
|
|
|
4552
4763
|
end
|
|
4553
4764
|
end
|
|
4554
4765
|
end
|
|
4766
|
+
|
|
4767
|
+
context 'when an id in nested attributes belongs to another parent' do
|
|
4768
|
+
let(:victim) { Person.create! }
|
|
4769
|
+
let(:attacker) { Person.create! }
|
|
4770
|
+
|
|
4771
|
+
context 'when the association is a has-many' do
|
|
4772
|
+
before do
|
|
4773
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
4774
|
+
Person.accepts_nested_attributes_for :posts
|
|
4775
|
+
end
|
|
4776
|
+
|
|
4777
|
+
let!(:victim_post) { victim.posts.create!(title: 'Private') }
|
|
4778
|
+
|
|
4779
|
+
it 'does not update the other parent\'s document' do
|
|
4780
|
+
expect { attacker.update!(posts_attributes: { '0' => { id: victim_post.id, title: 'Overwritten' } }) }
|
|
4781
|
+
.to raise_error(Mongoid::Errors::DocumentNotFound)
|
|
4782
|
+
expect(victim_post.reload.title).to eq('Private')
|
|
4783
|
+
end
|
|
4784
|
+
|
|
4785
|
+
it 'does not add the other parent\'s document to the association' do
|
|
4786
|
+
expect { attacker.update!(posts_attributes: { '0' => { id: victim_post.id, title: 'Overwritten' } }) }
|
|
4787
|
+
.to raise_error(Mongoid::Errors::DocumentNotFound)
|
|
4788
|
+
expect(attacker.reload.posts).to be_empty
|
|
4789
|
+
end
|
|
4790
|
+
|
|
4791
|
+
it 'does not update via a direct association assignment' do
|
|
4792
|
+
expect { attacker.update!(posts: { '0' => { id: victim_post.id, title: 'Overwritten' } }) }
|
|
4793
|
+
.to raise_error(Mongoid::Errors::DocumentNotFound)
|
|
4794
|
+
expect(victim_post.reload.title).to eq('Private')
|
|
4795
|
+
end
|
|
4796
|
+
end
|
|
4797
|
+
|
|
4798
|
+
context 'when the association is a has-and-belongs-to-many' do
|
|
4799
|
+
before do
|
|
4800
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
4801
|
+
Person.accepts_nested_attributes_for :preferences
|
|
4802
|
+
end
|
|
4803
|
+
|
|
4804
|
+
let!(:victim_preference) { victim.preferences.create!(name: 'Private') }
|
|
4805
|
+
|
|
4806
|
+
it 'does not update the other parent\'s document' do
|
|
4807
|
+
expect { attacker.update!(preferences_attributes: { '0' => { id: victim_preference.id, name: 'Overwritten' } }) }
|
|
4808
|
+
.to raise_error(Mongoid::Errors::DocumentNotFound)
|
|
4809
|
+
expect(victim_preference.reload.name).to eq('Private')
|
|
4810
|
+
end
|
|
4811
|
+
|
|
4812
|
+
it 'does not add the other parent\'s document to the association' do
|
|
4813
|
+
expect { attacker.update!(preferences_attributes: { '0' => { id: victim_preference.id, name: 'Overwritten' } }) }
|
|
4814
|
+
.to raise_error(Mongoid::Errors::DocumentNotFound)
|
|
4815
|
+
expect(attacker.reload.preferences).to be_empty
|
|
4816
|
+
end
|
|
4817
|
+
|
|
4818
|
+
it 'does not update via a direct association assignment' do
|
|
4819
|
+
expect { attacker.update!(preferences: { '0' => { id: victim_preference.id, name: 'Overwritten' } }) }
|
|
4820
|
+
.to raise_error(Mongoid::Errors::DocumentNotFound)
|
|
4821
|
+
expect(victim_preference.reload.name).to eq('Private')
|
|
4822
|
+
end
|
|
4823
|
+
end
|
|
4824
|
+
end
|
|
4555
4825
|
end
|
|
@@ -331,6 +331,42 @@ describe Mongoid::Clients::Factory do
|
|
|
331
331
|
end
|
|
332
332
|
end
|
|
333
333
|
end
|
|
334
|
+
|
|
335
|
+
context 'when bypass_auto_encryption is set' do
|
|
336
|
+
it 'warns that encryption is bypassed' do
|
|
337
|
+
expect(Mongoid::Warnings).to receive(:warn_bypass_auto_encryption)
|
|
338
|
+
|
|
339
|
+
described_class.send(
|
|
340
|
+
:build_auto_encryption_options,
|
|
341
|
+
{ auto_encryption_options: { bypass_auto_encryption: true, schema_map: {} } },
|
|
342
|
+
database_id
|
|
343
|
+
)
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
context 'when bypass_auto_encryption is not set' do
|
|
348
|
+
it 'does not warn' do
|
|
349
|
+
expect(Mongoid::Warnings).not_to receive(:warn_bypass_auto_encryption)
|
|
350
|
+
|
|
351
|
+
described_class.send(
|
|
352
|
+
:build_auto_encryption_options,
|
|
353
|
+
{ auto_encryption_options: { schema_map: {} } },
|
|
354
|
+
database_id
|
|
355
|
+
)
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
context 'when bypass_auto_encryption is false' do
|
|
360
|
+
it 'does not warn' do
|
|
361
|
+
expect(Mongoid::Warnings).not_to receive(:warn_bypass_auto_encryption)
|
|
362
|
+
|
|
363
|
+
described_class.send(
|
|
364
|
+
:build_auto_encryption_options,
|
|
365
|
+
{ auto_encryption_options: { bypass_auto_encryption: false, schema_map: {} } },
|
|
366
|
+
database_id
|
|
367
|
+
)
|
|
368
|
+
end
|
|
369
|
+
end
|
|
334
370
|
end
|
|
335
371
|
|
|
336
372
|
context 'when no name is provided' do
|
|
@@ -38,6 +38,24 @@ describe Mongoid::Config::Defaults do
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
shared_examples 'uses settings for 9.0' do
|
|
42
|
+
it 'uses settings for 9.0' do
|
|
43
|
+
expect(Mongoid.autosave_saves_unchanged_documents).to be true
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
shared_examples 'does not use settings for 9.0' do
|
|
48
|
+
it 'does not use settings for 9.0' do
|
|
49
|
+
expect(Mongoid.autosave_saves_unchanged_documents).to be false
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
shared_examples 'never allows reparenting via nested attributes' do
|
|
54
|
+
it 'leaves allow_reparenting_via_nested_attributes false' do
|
|
55
|
+
expect(Mongoid.allow_reparenting_via_nested_attributes).to be false
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
41
59
|
context 'when giving a valid version' do
|
|
42
60
|
before do
|
|
43
61
|
config.load_defaults(version)
|
|
@@ -52,6 +70,8 @@ describe Mongoid::Config::Defaults do
|
|
|
52
70
|
|
|
53
71
|
it_behaves_like 'uses settings for 8.0'
|
|
54
72
|
it_behaves_like 'uses settings for 8.1'
|
|
73
|
+
it_behaves_like 'uses settings for 9.0'
|
|
74
|
+
it_behaves_like 'never allows reparenting via nested attributes'
|
|
55
75
|
end
|
|
56
76
|
|
|
57
77
|
context 'when the given version is 8.1' do
|
|
@@ -59,6 +79,8 @@ describe Mongoid::Config::Defaults do
|
|
|
59
79
|
|
|
60
80
|
it_behaves_like 'does not use settings for 8.0'
|
|
61
81
|
it_behaves_like 'uses settings for 8.1'
|
|
82
|
+
it_behaves_like 'uses settings for 9.0'
|
|
83
|
+
it_behaves_like 'never allows reparenting via nested attributes'
|
|
62
84
|
end
|
|
63
85
|
|
|
64
86
|
context 'when the given version is 9.0' do
|
|
@@ -66,6 +88,17 @@ describe Mongoid::Config::Defaults do
|
|
|
66
88
|
|
|
67
89
|
it_behaves_like 'does not use settings for 8.0'
|
|
68
90
|
it_behaves_like 'does not use settings for 8.1'
|
|
91
|
+
it_behaves_like 'uses settings for 9.0'
|
|
92
|
+
it_behaves_like 'never allows reparenting via nested attributes'
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context 'when the given version is 9.1' do
|
|
96
|
+
let(:version) { 9.1 }
|
|
97
|
+
|
|
98
|
+
it_behaves_like 'does not use settings for 8.0'
|
|
99
|
+
it_behaves_like 'does not use settings for 8.1'
|
|
100
|
+
it_behaves_like 'does not use settings for 9.0'
|
|
101
|
+
it_behaves_like 'never allows reparenting via nested attributes'
|
|
69
102
|
end
|
|
70
103
|
end
|
|
71
104
|
|