mongoid 7.5.1 → 7.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/mongoid/association/embedded/batchable.rb +20 -3
- data/lib/mongoid/atomic/paths/embedded/many.rb +19 -0
- data/lib/mongoid/cacheable.rb +2 -2
- data/lib/mongoid/config.rb +6 -0
- data/lib/mongoid/contextual/mongo.rb +24 -7
- data/lib/mongoid/document.rb +8 -1
- data/lib/mongoid/persistence_context.rb +57 -6
- data/lib/mongoid/shardable.rb +35 -11
- data/lib/mongoid/version.rb +1 -1
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +21 -0
- data/spec/mongoid/association/embedded/embeds_many_models.rb +121 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +30 -0
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +20 -0
- data/spec/mongoid/attributes_spec.rb +44 -0
- data/spec/mongoid/cacheable_spec.rb +3 -3
- data/spec/mongoid/clients_spec.rb +30 -0
- data/spec/mongoid/config_spec.rb +7 -0
- data/spec/mongoid/contextual/mongo_spec.rb +23 -3
- data/spec/mongoid/persistence_context_spec.rb +26 -1
- data/spec/mongoid/shardable_models.rb +14 -0
- data/spec/mongoid/shardable_spec.rb +157 -51
- data/spec/mongoid_spec.rb +7 -1
- data/spec/shared/lib/mrss/lite_constraints.rb +8 -0
- data/spec/shared/shlib/server.sh +5 -5
- data.tar.gz.sig +0 -0
- metadata +633 -628
- 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: 27b0f244fe4642a684c267744270dd8e72b2b3ae1074b3621c24b31e979299b6
|
4
|
+
data.tar.gz: a79526be9f430f3777a35b2c27271175eca415c57ab2ae0346e3050b52f9311f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88c97668e4474dc109a910b2faa28f08b4c105b02e0f43611df3f2122e1232d9c3b2bfaedaf8aebebccf4358c40bc65c6bd04cfdc252c8ceca286aecf5b2d77e
|
7
|
+
data.tar.gz: ec9a56811c18fcf4cdeb238a7aa85eb350bc86513d9a883cd8f603122189af3da71bd0eea3a830ac06a26af30424648af935bf633f56ec740d045e94209b24fe
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -80,7 +80,8 @@ module Mongoid
|
|
80
80
|
def batch_replace(docs)
|
81
81
|
if docs.blank?
|
82
82
|
if _assigning? && !empty?
|
83
|
-
_base.delayed_atomic_sets.
|
83
|
+
_base.delayed_atomic_sets.delete(path)
|
84
|
+
clear_atomic_path_cache
|
84
85
|
_base.add_atomic_unset(first)
|
85
86
|
target_duplicate = _target.dup
|
86
87
|
pre_process_batch_remove(target_duplicate, :delete)
|
@@ -92,7 +93,8 @@ module Mongoid
|
|
92
93
|
_base.delayed_atomic_sets.clear unless _assigning?
|
93
94
|
docs = normalize_docs(docs).compact
|
94
95
|
_target.clear and _unscoped.clear
|
95
|
-
_base.delayed_atomic_unsets.
|
96
|
+
_base.delayed_atomic_unsets.delete(path)
|
97
|
+
clear_atomic_path_cache
|
96
98
|
inserts = execute_batch_set(docs)
|
97
99
|
add_atomic_sets(inserts)
|
98
100
|
end
|
@@ -234,7 +236,22 @@ module Mongoid
|
|
234
236
|
#
|
235
237
|
# @return [ String ] The atomic path.
|
236
238
|
def path
|
237
|
-
@path ||= _unscoped.
|
239
|
+
@path ||= if _unscoped.empty?
|
240
|
+
Mongoid::Atomic::Paths::Embedded::Many.position_without_document(_base, _association)
|
241
|
+
else
|
242
|
+
_unscoped.first.atomic_path
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Clear the cache for path and atomic_paths. This method is used when
|
247
|
+
# the path method is used, and the association has not been set on the
|
248
|
+
# document yet, which can cause path and atomic_paths to be calculated
|
249
|
+
# incorrectly later.
|
250
|
+
#
|
251
|
+
# @api private
|
252
|
+
def clear_atomic_path_cache
|
253
|
+
self.path = nil
|
254
|
+
_base.instance_variable_set("@atomic_paths", nil)
|
238
255
|
end
|
239
256
|
|
240
257
|
# Set the atomic path.
|
@@ -34,6 +34,25 @@ module Mongoid
|
|
34
34
|
locator = document.new_record? ? "" : ".#{document._index}"
|
35
35
|
"#{pos}#{"." unless pos.blank?}#{document._association.store_as}#{locator}"
|
36
36
|
end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
|
40
|
+
# Get the position of where the document would go for the given
|
41
|
+
# association. The use case for this function is when trying to
|
42
|
+
# persist an empty list for an embedded association. All of the
|
43
|
+
# existing functions for getting the position to store a document
|
44
|
+
# require passing in a document to store, which we don't have when
|
45
|
+
# trying to store the empty list.
|
46
|
+
#
|
47
|
+
# @param [ Document ] parent The parent document to store in.
|
48
|
+
# @param [ Association ] association The association.
|
49
|
+
#
|
50
|
+
# @return [ String ] The position string.
|
51
|
+
def position_without_document(parent, association)
|
52
|
+
pos = parent.atomic_position
|
53
|
+
"#{pos}#{"." unless pos.blank?}#{association.store_as}"
|
54
|
+
end
|
55
|
+
end
|
37
56
|
end
|
38
57
|
end
|
39
58
|
end
|
data/lib/mongoid/cacheable.rb
CHANGED
@@ -15,7 +15,7 @@ module Mongoid
|
|
15
15
|
# plural model name.
|
16
16
|
#
|
17
17
|
# If new_record? - will append /new
|
18
|
-
# If not - will append /id-updated_at.
|
18
|
+
# If not - will append /id-updated_at.to_formatted_s(cache_timestamp_format)
|
19
19
|
# Without updated_at - will append /id
|
20
20
|
#
|
21
21
|
# This is usually called inside a cache() block
|
@@ -26,7 +26,7 @@ module Mongoid
|
|
26
26
|
# @return [ String ] the string with or without updated_at
|
27
27
|
def cache_key
|
28
28
|
return "#{model_key}/new" if new_record?
|
29
|
-
return "#{model_key}/#{_id}-#{updated_at.utc.
|
29
|
+
return "#{model_key}/#{_id}-#{updated_at.utc.to_formatted_s(cache_timestamp_format)}" if do_or_do_not(:updated_at)
|
30
30
|
"#{model_key}/#{_id}"
|
31
31
|
end
|
32
32
|
end
|
data/lib/mongoid/config.rb
CHANGED
@@ -116,6 +116,12 @@ module Mongoid
|
|
116
116
|
# using and's instead of overwriting them.
|
117
117
|
option :overwrite_chained_operators, default: true
|
118
118
|
|
119
|
+
# When this flag is true, the attributes method on a document will return
|
120
|
+
# a BSON::Document when that document is retrieved from the database, and
|
121
|
+
# a Hash otherwise. When this flag is false, the attributes method will
|
122
|
+
# always return a Hash.
|
123
|
+
option :legacy_attributes, default: true
|
124
|
+
|
119
125
|
# Has Mongoid been configured? This is checking that at least a valid
|
120
126
|
# client config exists.
|
121
127
|
#
|
@@ -260,16 +260,16 @@ module Mongoid
|
|
260
260
|
#
|
261
261
|
# @return [ Document ] The first document.
|
262
262
|
def first(limit_or_opts = nil)
|
263
|
-
limit = limit_or_opts
|
263
|
+
limit, opts = extract_limit_and_opts(limit_or_opts)
|
264
264
|
if cached? && cache_loaded?
|
265
265
|
return limit ? documents.first(limit) : documents.first
|
266
266
|
end
|
267
267
|
try_numbered_cache(:first, limit) do
|
268
|
-
if
|
268
|
+
if opts.key?(:id_sort)
|
269
269
|
Mongoid::Warnings.warn_id_sort_deprecated
|
270
270
|
end
|
271
271
|
sorted_view = view
|
272
|
-
if sort = view.sort || ({ _id: 1 } unless
|
272
|
+
if sort = view.sort || ({ _id: 1 } unless opts[:id_sort] == :none)
|
273
273
|
sorted_view = view.sort(sort)
|
274
274
|
end
|
275
275
|
if raw_docs = sorted_view.limit(limit || 1).to_a
|
@@ -376,12 +376,12 @@ module Mongoid
|
|
376
376
|
#
|
377
377
|
# @return [ Document ] The last document.
|
378
378
|
def last(limit_or_opts = nil)
|
379
|
-
limit = limit_or_opts
|
379
|
+
limit, opts = extract_limit_and_opts(limit_or_opts)
|
380
380
|
if cached? && cache_loaded?
|
381
381
|
return limit ? documents.last(limit) : documents.last
|
382
382
|
end
|
383
383
|
res = try_numbered_cache(:last, limit) do
|
384
|
-
with_inverse_sorting(
|
384
|
+
with_inverse_sorting(opts) do
|
385
385
|
if raw_docs = view.limit(limit || 1).to_a
|
386
386
|
process_raw_docs(raw_docs, limit)
|
387
387
|
end
|
@@ -612,6 +612,23 @@ module Mongoid
|
|
612
612
|
end
|
613
613
|
end
|
614
614
|
|
615
|
+
# Extract the limit and opts from the given argument, so that code
|
616
|
+
# can operate without having to worry about the current type and
|
617
|
+
# state of the argument.
|
618
|
+
#
|
619
|
+
# @param [ nil | Integer | Hash ] limit_or_opts The value to pull the
|
620
|
+
# limit and option hash from.
|
621
|
+
#
|
622
|
+
# @return [ Array<nil | Integer, Hash> ] A 2-array of the limit and the
|
623
|
+
# option hash.
|
624
|
+
def extract_limit_and_opts(limit_or_opts)
|
625
|
+
case limit_or_opts
|
626
|
+
when nil, Integer then [ limit_or_opts, {} ]
|
627
|
+
when Hash then [ nil, limit_or_opts ]
|
628
|
+
else raise ArgumentError, "expected nil, Integer, or Hash"
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
615
632
|
# Update the documents for the provided method.
|
616
633
|
#
|
617
634
|
# @api private
|
@@ -676,10 +693,10 @@ module Mongoid
|
|
676
693
|
# @example Apply the inverse sorting params to the given block
|
677
694
|
# context.with_inverse_sorting
|
678
695
|
def with_inverse_sorting(opts = {})
|
679
|
-
Mongoid::Warnings.warn_id_sort_deprecated if opts.
|
696
|
+
Mongoid::Warnings.warn_id_sort_deprecated if opts.key?(:id_sort)
|
680
697
|
|
681
698
|
begin
|
682
|
-
if sort = criteria.options[:sort] || ( { _id: 1 } unless opts
|
699
|
+
if sort = criteria.options[:sort] || ( { _id: 1 } unless opts[:id_sort] == :none )
|
683
700
|
@view = view.sort(Hash[sort.map{|k, v| [k, -1*v]}])
|
684
701
|
end
|
685
702
|
yield
|
data/lib/mongoid/document.rb
CHANGED
@@ -277,8 +277,15 @@ module Mongoid
|
|
277
277
|
# criteria.
|
278
278
|
#
|
279
279
|
# @return [ Document ] A new document.
|
280
|
+
#
|
281
|
+
# @api private
|
280
282
|
def instantiate(attrs = nil, selected_fields = nil)
|
281
|
-
attributes =
|
283
|
+
attributes = if Mongoid.legacy_attributes
|
284
|
+
attrs
|
285
|
+
else
|
286
|
+
attrs&.to_h
|
287
|
+
end || {}
|
288
|
+
|
282
289
|
doc = allocate
|
283
290
|
doc.__selected_fields = selected_fields
|
284
291
|
doc.instance_variable_set(:@attributes, attributes)
|
@@ -122,6 +122,21 @@ module Mongoid
|
|
122
122
|
options == other.options
|
123
123
|
end
|
124
124
|
|
125
|
+
# Whether the client of the context can be reused later, and therefore should
|
126
|
+
# not be closed.
|
127
|
+
#
|
128
|
+
# If the persistence context is requested with :client option only, it means
|
129
|
+
# that the context should use a client configured in mongoid.yml.
|
130
|
+
# Such clients should not be closed when the context is cleared since they
|
131
|
+
# will be reused later.
|
132
|
+
#
|
133
|
+
# @return [ true | false ] True if client can be reused, otherwise false.
|
134
|
+
#
|
135
|
+
# @api private
|
136
|
+
def reusable_client?
|
137
|
+
@options.keys == [:client]
|
138
|
+
end
|
139
|
+
|
125
140
|
private
|
126
141
|
|
127
142
|
def set_options!(opts)
|
@@ -172,8 +187,7 @@ module Mongoid
|
|
172
187
|
#
|
173
188
|
# @return [ Mongoid::PersistenceContext ] The persistence context for the object.
|
174
189
|
def set(object, options_or_context)
|
175
|
-
|
176
|
-
existing_context = Thread.current[key]
|
190
|
+
existing_context = get_context(object)
|
177
191
|
existing_options = if existing_context
|
178
192
|
existing_context.options
|
179
193
|
else
|
@@ -184,7 +198,7 @@ module Mongoid
|
|
184
198
|
end
|
185
199
|
new_options = existing_options.merge(options_or_context)
|
186
200
|
context = PersistenceContext.new(object, new_options)
|
187
|
-
|
201
|
+
store_context(object, context)
|
188
202
|
end
|
189
203
|
|
190
204
|
# Get the persistence context for a particular class or model instance.
|
@@ -196,7 +210,7 @@ module Mongoid
|
|
196
210
|
#
|
197
211
|
# @return [ Mongoid::PersistenceContext ] The persistence context for the object.
|
198
212
|
def get(object)
|
199
|
-
|
213
|
+
get_context(object)
|
200
214
|
end
|
201
215
|
|
202
216
|
# Clear the persistence context for a particular class or model instance.
|
@@ -211,11 +225,48 @@ module Mongoid
|
|
211
225
|
def clear(object, cluster = nil, original_context = nil)
|
212
226
|
if context = get(object)
|
213
227
|
unless cluster.nil? || context.cluster.equal?(cluster)
|
214
|
-
context.client.close
|
228
|
+
context.client.close unless context.reusable_client?
|
215
229
|
end
|
216
230
|
end
|
217
231
|
ensure
|
218
|
-
|
232
|
+
store_context(object, original_context)
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
# Key to store persistence contexts in the thread local storage.
|
238
|
+
#
|
239
|
+
# @api private
|
240
|
+
PERSISTENCE_CONTEXT_KEY = :"[mongoid]:persistence_context"
|
241
|
+
|
242
|
+
# Get the persistence context for a given object from the thread local
|
243
|
+
# storage.
|
244
|
+
#
|
245
|
+
# @param [ Object ] object Object to get the persistance context for.
|
246
|
+
#
|
247
|
+
# @return [ Mongoid::PersistenceContext | nil ] The persistence context
|
248
|
+
# for the object if previously stored, otherwise nil.
|
249
|
+
#
|
250
|
+
# @api private
|
251
|
+
def get_context(object)
|
252
|
+
Thread.current[PERSISTENCE_CONTEXT_KEY] ||= {}
|
253
|
+
Thread.current[PERSISTENCE_CONTEXT_KEY][object.object_id]
|
254
|
+
end
|
255
|
+
|
256
|
+
# Store persistence context for a given object in the thread local
|
257
|
+
# storage.
|
258
|
+
#
|
259
|
+
# @param [ Object ] object Object to store the persistance context for.
|
260
|
+
# @param [ Mongoid::PersistenceContext ] context Context to store
|
261
|
+
#
|
262
|
+
# @api private
|
263
|
+
def store_context(object, context)
|
264
|
+
if context.nil?
|
265
|
+
Thread.current[PERSISTENCE_CONTEXT_KEY]&.delete(object.object_id)
|
266
|
+
else
|
267
|
+
Thread.current[PERSISTENCE_CONTEXT_KEY] ||= {}
|
268
|
+
Thread.current[PERSISTENCE_CONTEXT_KEY][object.object_id] = context
|
269
|
+
end
|
219
270
|
end
|
220
271
|
end
|
221
272
|
end
|
data/lib/mongoid/shardable.rb
CHANGED
@@ -47,18 +47,22 @@ module Mongoid
|
|
47
47
|
self.class.shard_key_fields
|
48
48
|
end
|
49
49
|
|
50
|
-
# Returns the selector that would match the
|
51
|
-
#
|
50
|
+
# Returns the selector that would match the defined shard keys. If
|
51
|
+
# `prefer_persisted` is false (the default), it uses the current values
|
52
|
+
# of the specified shard keys, otherwise, it will try to use whatever value
|
53
|
+
# was most recently persisted.
|
54
|
+
#
|
55
|
+
# @param [ true | false ] prefer_persisted Whether to use the current
|
56
|
+
# value of the shard key fields, or to use their most recently persisted
|
57
|
+
# values.
|
52
58
|
#
|
53
59
|
# @return [ Hash ] The shard key selector.
|
54
60
|
#
|
55
61
|
# @api private
|
56
|
-
def shard_key_selector
|
57
|
-
|
58
|
-
|
59
|
-
selector[field.to_s] = send(field)
|
62
|
+
def shard_key_selector(prefer_persisted: false)
|
63
|
+
shard_key_fields.each_with_object({}) do |field, selector|
|
64
|
+
selector[field.to_s] = shard_key_field_value(field.to_s, prefer_persisted: prefer_persisted)
|
60
65
|
end
|
61
|
-
selector
|
62
66
|
end
|
63
67
|
|
64
68
|
# Returns the selector that would match the existing version of this
|
@@ -72,11 +76,31 @@ module Mongoid
|
|
72
76
|
#
|
73
77
|
# @api private
|
74
78
|
def shard_key_selector_in_db
|
75
|
-
|
76
|
-
|
77
|
-
|
79
|
+
shard_key_selector(prefer_persisted: true)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns the value for the named shard key. If the field identifies
|
83
|
+
# an embedded document, the key will be parsed and recursively evaluated.
|
84
|
+
# If `prefer_persisted` is true, the value last persisted to the database
|
85
|
+
# will be returned, regardless of what the current value of the attribute
|
86
|
+
# may be.
|
87
|
+
#
|
88
|
+
# @param [String] field The name of the field to evaluate
|
89
|
+
# @param [ true|false ] prefer_persisted Whether or not to prefer the
|
90
|
+
# persisted value over the current value.
|
91
|
+
#
|
92
|
+
# @return [ Object ] The value of the named field.
|
93
|
+
#
|
94
|
+
# @api private
|
95
|
+
def shard_key_field_value(field, prefer_persisted:)
|
96
|
+
if field.include?(".")
|
97
|
+
relation, remaining = field.split(".", 2)
|
98
|
+
send(relation)&.shard_key_field_value(remaining, prefer_persisted: prefer_persisted)
|
99
|
+
elsif prefer_persisted && !new_record?
|
100
|
+
attribute_was(field)
|
101
|
+
else
|
102
|
+
send(field)
|
78
103
|
end
|
79
|
-
selector
|
80
104
|
end
|
81
105
|
|
82
106
|
module ClassMethods
|
data/lib/mongoid/version.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
|
+
require_relative '../embeds_many_models.rb'
|
4
5
|
|
5
6
|
describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
|
6
7
|
|
@@ -4649,4 +4650,24 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
|
|
4649
4650
|
end
|
4650
4651
|
end
|
4651
4652
|
end
|
4653
|
+
|
4654
|
+
context "when using assign_attributes with an already populated array" do
|
4655
|
+
let(:post) { EmmPost.create! }
|
4656
|
+
|
4657
|
+
before do
|
4658
|
+
post.assign_attributes(company_tags: [{id: BSON::ObjectId.new, title: 'a'}],
|
4659
|
+
user_tags: [{id: BSON::ObjectId.new, title: 'b'}])
|
4660
|
+
post.save!
|
4661
|
+
post.reload
|
4662
|
+
post.assign_attributes(company_tags: [{id: BSON::ObjectId.new, title: 'c'}],
|
4663
|
+
user_tags: [])
|
4664
|
+
post.save!
|
4665
|
+
post.reload
|
4666
|
+
end
|
4667
|
+
|
4668
|
+
it "has the correct embedded documents" do
|
4669
|
+
expect(post.company_tags.length).to eq(1)
|
4670
|
+
expect(post.company_tags.first.title).to eq("c")
|
4671
|
+
end
|
4672
|
+
end
|
4652
4673
|
end
|
@@ -67,3 +67,124 @@ class EmmOuter
|
|
67
67
|
|
68
68
|
field :level, :type => Integer
|
69
69
|
end
|
70
|
+
|
71
|
+
class EmmCustomerAddress
|
72
|
+
include Mongoid::Document
|
73
|
+
|
74
|
+
embedded_in :addressable, polymorphic: true, inverse_of: :work_address
|
75
|
+
end
|
76
|
+
|
77
|
+
class EmmFriend
|
78
|
+
include Mongoid::Document
|
79
|
+
|
80
|
+
embedded_in :befriendable, polymorphic: true
|
81
|
+
end
|
82
|
+
|
83
|
+
class EmmCustomer
|
84
|
+
include Mongoid::Document
|
85
|
+
|
86
|
+
embeds_one :home_address, class_name: 'EmmCustomerAddress', as: :addressable
|
87
|
+
embeds_one :work_address, class_name: 'EmmCustomerAddress', as: :addressable
|
88
|
+
|
89
|
+
embeds_many :close_friends, class_name: 'EmmFriend', as: :befriendable
|
90
|
+
embeds_many :acquaintances, class_name: 'EmmFriend', as: :befriendable
|
91
|
+
end
|
92
|
+
|
93
|
+
class EmmUser
|
94
|
+
include Mongoid::Document
|
95
|
+
include Mongoid::Timestamps
|
96
|
+
|
97
|
+
embeds_many :orders, class_name: 'EmmOrder'
|
98
|
+
end
|
99
|
+
|
100
|
+
class EmmOrder
|
101
|
+
include Mongoid::Document
|
102
|
+
|
103
|
+
field :amount, type: Integer
|
104
|
+
|
105
|
+
embedded_in :user, class_name: 'EmmUser'
|
106
|
+
end
|
107
|
+
|
108
|
+
module EmmSpec
|
109
|
+
# There is also a top-level Car class defined.
|
110
|
+
class Car
|
111
|
+
include Mongoid::Document
|
112
|
+
|
113
|
+
embeds_many :doors
|
114
|
+
end
|
115
|
+
|
116
|
+
class Door
|
117
|
+
include Mongoid::Document
|
118
|
+
|
119
|
+
embedded_in :car
|
120
|
+
end
|
121
|
+
|
122
|
+
class Tank
|
123
|
+
include Mongoid::Document
|
124
|
+
|
125
|
+
embeds_many :guns
|
126
|
+
embeds_many :emm_turrets
|
127
|
+
# This association references a model that is not in our module,
|
128
|
+
# and it does not define class_name hence Mongoid will not be able to
|
129
|
+
# figure out the inverse for this association.
|
130
|
+
embeds_many :emm_hatches
|
131
|
+
|
132
|
+
# class_name is intentionally unqualified, references a class in the
|
133
|
+
# same module. Rails permits class_name to be unqualified like this.
|
134
|
+
embeds_many :launchers, class_name: 'Launcher'
|
135
|
+
end
|
136
|
+
|
137
|
+
class Gun
|
138
|
+
include Mongoid::Document
|
139
|
+
|
140
|
+
embedded_in :tank
|
141
|
+
end
|
142
|
+
|
143
|
+
class Launcher
|
144
|
+
include Mongoid::Document
|
145
|
+
|
146
|
+
# class_name is intentionally unqualified.
|
147
|
+
embedded_in :tank, class_name: 'Tank'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# This is intentionally on top level.
|
152
|
+
class EmmTurret
|
153
|
+
include Mongoid::Document
|
154
|
+
|
155
|
+
embedded_in :tank, class_name: 'EmmSpec::Tank'
|
156
|
+
end
|
157
|
+
|
158
|
+
# This is intentionally on top level.
|
159
|
+
class EmmHatch
|
160
|
+
include Mongoid::Document
|
161
|
+
|
162
|
+
# No :class_name option on this association intentionally.
|
163
|
+
embedded_in :tank
|
164
|
+
end
|
165
|
+
|
166
|
+
class EmmPost
|
167
|
+
include Mongoid::Document
|
168
|
+
|
169
|
+
embeds_many :company_tags, class_name: "EmmCompanyTag"
|
170
|
+
embeds_many :user_tags, class_name: "EmmUserTag"
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
class EmmCompanyTag
|
175
|
+
include Mongoid::Document
|
176
|
+
|
177
|
+
field :title, type: String
|
178
|
+
|
179
|
+
embedded_in :post, class_name: "EmmPost"
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
class EmmUserTag
|
184
|
+
include Mongoid::Document
|
185
|
+
|
186
|
+
field :title, type: String
|
187
|
+
|
188
|
+
embedded_in :post, class_name: "EmmPost"
|
189
|
+
end
|
190
|
+
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
|
+
require_relative "../has_and_belongs_to_many_models.rb"
|
4
5
|
|
5
6
|
describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
|
6
7
|
|
@@ -3770,4 +3771,33 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
|
|
3770
3771
|
expect(p2.d_ids).to match_array([d2.id])
|
3771
3772
|
end
|
3772
3773
|
end
|
3774
|
+
|
3775
|
+
# This test is for MONGOID-5344 which tests that the initial call to
|
3776
|
+
# signature_ids refers to the same array as subsequent calls to signature_ids.
|
3777
|
+
# Prior to the change in that ticket, this test broke because the array
|
3778
|
+
# returned from write_attribute (which is triggered the first time the
|
3779
|
+
# foreign key array is referenced, to set the default), refers to a different
|
3780
|
+
# array to the one stored in the attributes hash. This happened because,
|
3781
|
+
# when retrieving a document from the database, the attributes hash is actually
|
3782
|
+
# a BSON::Document, which applies a transformation to the array before
|
3783
|
+
# storing it.
|
3784
|
+
context "when executing concat on foreign key array from the db" do
|
3785
|
+
config_override :legacy_attributes, false
|
3786
|
+
|
3787
|
+
before do
|
3788
|
+
HabtmmContract.create!
|
3789
|
+
HabtmmSignature.create!
|
3790
|
+
end
|
3791
|
+
|
3792
|
+
let!(:contract) { HabtmmContract.first }
|
3793
|
+
let!(:signature) { HabtmmSignature.first }
|
3794
|
+
|
3795
|
+
before do
|
3796
|
+
contract.signature_ids.concat([signature.id])
|
3797
|
+
end
|
3798
|
+
|
3799
|
+
it "works on the first attempt" do
|
3800
|
+
expect(contract.signature_ids).to eq([signature.id])
|
3801
|
+
end
|
3802
|
+
end
|
3773
3803
|
end
|
@@ -4089,4 +4089,24 @@ describe Mongoid::Association::Referenced::HasMany::Proxy do
|
|
4089
4089
|
expect(band.same_name).to eq([agent])
|
4090
4090
|
end
|
4091
4091
|
end
|
4092
|
+
|
4093
|
+
context "when executing concat on foreign key array from the db" do
|
4094
|
+
config_override :legacy_attributes, false
|
4095
|
+
|
4096
|
+
before do
|
4097
|
+
Agent.create!
|
4098
|
+
Basic.create!
|
4099
|
+
end
|
4100
|
+
|
4101
|
+
let!(:agent) { Agent.first }
|
4102
|
+
let!(:basic) { Basic.first }
|
4103
|
+
|
4104
|
+
before do
|
4105
|
+
agent.basic_ids.concat([basic.id])
|
4106
|
+
end
|
4107
|
+
|
4108
|
+
it "works on the first attempt" do
|
4109
|
+
expect(agent.basic_ids).to eq([basic.id])
|
4110
|
+
end
|
4111
|
+
end
|
4092
4112
|
end
|
@@ -1675,6 +1675,50 @@ describe Mongoid::Attributes do
|
|
1675
1675
|
end
|
1676
1676
|
end
|
1677
1677
|
end
|
1678
|
+
|
1679
|
+
context "when comparing the object_ids of the written value" do
|
1680
|
+
config_override :legacy_attributes, false
|
1681
|
+
|
1682
|
+
before do
|
1683
|
+
Person.create!
|
1684
|
+
end
|
1685
|
+
|
1686
|
+
let(:person) do
|
1687
|
+
Person.first
|
1688
|
+
end
|
1689
|
+
|
1690
|
+
context "when the field is not resizable" do
|
1691
|
+
let(:test) do
|
1692
|
+
person.write_attribute(:test, "aliased field to test")
|
1693
|
+
end
|
1694
|
+
|
1695
|
+
it "has the same object_id as the attributes hash value" do
|
1696
|
+
expect(test.object_id).to eq(person.test.object_id)
|
1697
|
+
end
|
1698
|
+
end
|
1699
|
+
|
1700
|
+
context "when the field is resizable" do
|
1701
|
+
|
1702
|
+
let(:arrays) do
|
1703
|
+
person.write_attribute(:arrays, [])
|
1704
|
+
end
|
1705
|
+
|
1706
|
+
it "has the same object_id as the attributes hash value" do
|
1707
|
+
expect(arrays.object_id).to eq(person.arrays.object_id)
|
1708
|
+
end
|
1709
|
+
end
|
1710
|
+
|
1711
|
+
context "when the field is a HABTM foreign key array" do
|
1712
|
+
|
1713
|
+
let(:preference_ids) do
|
1714
|
+
person.write_attribute(:preference_ids, [])
|
1715
|
+
end
|
1716
|
+
|
1717
|
+
it "has the same object_id as the attributes hash value" do
|
1718
|
+
expect(preference_ids.object_id).to eq(person.preference_ids.object_id)
|
1719
|
+
end
|
1720
|
+
end
|
1721
|
+
end
|
1678
1722
|
end
|
1679
1723
|
|
1680
1724
|
describe "#typed_value_for" do
|
@@ -45,7 +45,7 @@ describe Mongoid::Cacheable do
|
|
45
45
|
context "with the default cache_timestamp_format" do
|
46
46
|
|
47
47
|
let!(:updated_at) do
|
48
|
-
document.updated_at.utc.
|
48
|
+
document.updated_at.utc.to_formatted_s(:nsec)
|
49
49
|
end
|
50
50
|
|
51
51
|
it "has the id and updated_at key name" do
|
@@ -64,7 +64,7 @@ describe Mongoid::Cacheable do
|
|
64
64
|
end
|
65
65
|
|
66
66
|
let!(:updated_at) do
|
67
|
-
document.updated_at.utc.
|
67
|
+
document.updated_at.utc.to_formatted_s(:number)
|
68
68
|
end
|
69
69
|
|
70
70
|
it "has the id and updated_at key name" do
|
@@ -103,7 +103,7 @@ describe Mongoid::Cacheable do
|
|
103
103
|
end
|
104
104
|
|
105
105
|
let!(:updated_at) do
|
106
|
-
agent.updated_at.utc.
|
106
|
+
agent.updated_at.utc.to_formatted_s(:nsec)
|
107
107
|
end
|
108
108
|
|
109
109
|
it "has the id and updated_at key name" do
|