mongoid 8.0.5 → 8.1.0

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.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +3 -3
  4. data/README.md +3 -3
  5. data/Rakefile +0 -25
  6. data/lib/config/locales/en.yml +46 -14
  7. data/lib/mongoid/association/accessors.rb +2 -2
  8. data/lib/mongoid/association/builders.rb +1 -1
  9. data/lib/mongoid/association/embedded/batchable.rb +2 -2
  10. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
  11. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -1
  12. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +3 -2
  13. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +6 -6
  14. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +1 -1
  15. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
  16. data/lib/mongoid/association/nested/one.rb +40 -2
  17. data/lib/mongoid/association/proxy.rb +1 -1
  18. data/lib/mongoid/association/referenced/counter_cache.rb +2 -2
  19. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +1 -1
  20. data/lib/mongoid/association/referenced/has_many/enumerable.rb +2 -2
  21. data/lib/mongoid/association/referenced/has_many/proxy.rb +3 -3
  22. data/lib/mongoid/association/reflections.rb +2 -2
  23. data/lib/mongoid/atomic.rb +0 -7
  24. data/lib/mongoid/attributes/dynamic.rb +1 -1
  25. data/lib/mongoid/attributes/nested.rb +2 -2
  26. data/lib/mongoid/attributes/projector.rb +1 -1
  27. data/lib/mongoid/attributes/readonly.rb +1 -1
  28. data/lib/mongoid/attributes.rb +8 -2
  29. data/lib/mongoid/changeable.rb +107 -5
  30. data/lib/mongoid/clients/storage_options.rb +2 -5
  31. data/lib/mongoid/clients/validators/storage.rb +1 -13
  32. data/lib/mongoid/collection_configurable.rb +58 -0
  33. data/lib/mongoid/composable.rb +2 -0
  34. data/lib/mongoid/config/defaults.rb +60 -0
  35. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  36. data/lib/mongoid/config/validators.rb +1 -0
  37. data/lib/mongoid/config.rb +101 -0
  38. data/lib/mongoid/contextual/atomic.rb +1 -1
  39. data/lib/mongoid/contextual/memory.rb +233 -33
  40. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  41. data/lib/mongoid/contextual/mongo.rb +373 -113
  42. data/lib/mongoid/contextual/none.rb +162 -7
  43. data/lib/mongoid/contextual.rb +12 -0
  44. data/lib/mongoid/criteria/findable.rb +2 -2
  45. data/lib/mongoid/criteria/includable.rb +4 -3
  46. data/lib/mongoid/criteria/queryable/key.rb +1 -1
  47. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
  48. data/lib/mongoid/criteria/queryable/optional.rb +8 -8
  49. data/lib/mongoid/criteria/queryable/selectable.rb +43 -12
  50. data/lib/mongoid/criteria.rb +6 -5
  51. data/lib/mongoid/deprecable.rb +1 -1
  52. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  53. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  54. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  55. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  56. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  57. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
  58. data/lib/mongoid/errors.rb +4 -1
  59. data/lib/mongoid/extensions/object.rb +2 -2
  60. data/lib/mongoid/extensions/time.rb +2 -0
  61. data/lib/mongoid/fields/localized.rb +10 -0
  62. data/lib/mongoid/fields/standard.rb +10 -0
  63. data/lib/mongoid/fields.rb +69 -13
  64. data/lib/mongoid/findable.rb +27 -3
  65. data/lib/mongoid/interceptable.rb +7 -6
  66. data/lib/mongoid/matcher/eq_impl.rb +1 -1
  67. data/lib/mongoid/matcher/type.rb +1 -1
  68. data/lib/mongoid/persistable/creatable.rb +1 -0
  69. data/lib/mongoid/persistable/deletable.rb +1 -1
  70. data/lib/mongoid/persistable/savable.rb +13 -1
  71. data/lib/mongoid/persistable/unsettable.rb +2 -2
  72. data/lib/mongoid/persistable/updatable.rb +51 -1
  73. data/lib/mongoid/persistable/upsertable.rb +20 -1
  74. data/lib/mongoid/persistable.rb +3 -0
  75. data/lib/mongoid/query_cache.rb +5 -1
  76. data/lib/mongoid/railties/database.rake +7 -2
  77. data/lib/mongoid/reloadable.rb +5 -3
  78. data/lib/mongoid/stateful.rb +22 -1
  79. data/lib/mongoid/tasks/database.rake +12 -0
  80. data/lib/mongoid/tasks/database.rb +20 -0
  81. data/lib/mongoid/utils.rb +22 -0
  82. data/lib/mongoid/validatable/macros.rb +5 -5
  83. data/lib/mongoid/validatable.rb +4 -1
  84. data/lib/mongoid/version.rb +1 -1
  85. data/lib/mongoid/warnings.rb +17 -1
  86. data/lib/mongoid.rb +16 -3
  87. data/spec/integration/app_spec.rb +2 -2
  88. data/spec/integration/callbacks_models.rb +37 -0
  89. data/spec/integration/callbacks_spec.rb +134 -0
  90. data/spec/integration/discriminator_key_spec.rb +4 -5
  91. data/spec/integration/i18n_fallbacks_spec.rb +3 -2
  92. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +27 -0
  93. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +20 -25
  94. data/spec/mongoid/association/embedded/embeds_many_models.rb +1 -0
  95. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
  96. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -18
  97. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +5 -27
  98. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +9 -50
  99. data/spec/mongoid/association/syncable_spec.rb +1 -1
  100. data/spec/mongoid/attributes_spec.rb +3 -6
  101. data/spec/mongoid/changeable_spec.rb +299 -24
  102. data/spec/mongoid/clients_spec.rb +122 -13
  103. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  104. data/spec/mongoid/config/defaults_spec.rb +160 -0
  105. data/spec/mongoid/config_spec.rb +154 -18
  106. data/spec/mongoid/contextual/memory_spec.rb +332 -76
  107. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  108. data/spec/mongoid/contextual/mongo_spec.rb +995 -36
  109. data/spec/mongoid/contextual/none_spec.rb +49 -2
  110. data/spec/mongoid/copyable_spec.rb +3 -11
  111. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -10
  112. data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
  113. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +419 -0
  114. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -1
  115. data/spec/mongoid/criteria/queryable/selector_spec.rb +1 -1
  116. data/spec/mongoid/criteria_projection_spec.rb +1 -4
  117. data/spec/mongoid/criteria_spec.rb +5 -9
  118. data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
  119. data/spec/mongoid/extensions/time_spec.rb +8 -43
  120. data/spec/mongoid/extensions/time_with_zone_spec.rb +7 -52
  121. data/spec/mongoid/fields/localized_spec.rb +46 -28
  122. data/spec/mongoid/fields_spec.rb +136 -34
  123. data/spec/mongoid/findable_spec.rb +391 -34
  124. data/spec/mongoid/indexable_spec.rb +16 -10
  125. data/spec/mongoid/interceptable_spec.rb +15 -3
  126. data/spec/mongoid/persistable/deletable_spec.rb +26 -6
  127. data/spec/mongoid/persistable/destroyable_spec.rb +26 -6
  128. data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
  129. data/spec/mongoid/persistable/logical_spec.rb +37 -0
  130. data/spec/mongoid/persistable/poppable_spec.rb +36 -0
  131. data/spec/mongoid/persistable/pullable_spec.rb +72 -0
  132. data/spec/mongoid/persistable/pushable_spec.rb +72 -0
  133. data/spec/mongoid/persistable/renamable_spec.rb +36 -0
  134. data/spec/mongoid/persistable/savable_spec.rb +96 -0
  135. data/spec/mongoid/persistable/settable_spec.rb +37 -0
  136. data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
  137. data/spec/mongoid/persistable/updatable_spec.rb +20 -28
  138. data/spec/mongoid/persistable/upsertable_spec.rb +80 -6
  139. data/spec/mongoid/persistence_context_spec.rb +7 -57
  140. data/spec/mongoid/query_cache_spec.rb +56 -61
  141. data/spec/mongoid/reloadable_spec.rb +24 -28
  142. data/spec/mongoid/scopable_spec.rb +70 -0
  143. data/spec/mongoid/serializable_spec.rb +9 -30
  144. data/spec/mongoid/stateful_spec.rb +122 -8
  145. data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
  146. data/spec/mongoid/tasks/database_spec.rb +127 -0
  147. data/spec/mongoid/timestamps_spec.rb +9 -11
  148. data/spec/mongoid/touchable_spec.rb +277 -5
  149. data/spec/mongoid/touchable_spec_models.rb +3 -1
  150. data/spec/mongoid/traversable_spec.rb +9 -24
  151. data/spec/mongoid/validatable/uniqueness_spec.rb +2 -3
  152. data/spec/mongoid_spec.rb +36 -10
  153. data/spec/shared/lib/mrss/docker_runner.rb +7 -0
  154. data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
  155. data/spec/shared/lib/mrss/lite_constraints.rb +10 -2
  156. data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
  157. data/spec/shared/lib/mrss/utils.rb +28 -6
  158. data/spec/shared/share/Dockerfile.erb +36 -40
  159. data/spec/shared/shlib/server.sh +32 -8
  160. data/spec/shared/shlib/set_env.sh +4 -4
  161. data/spec/spec_helper.rb +5 -0
  162. data/spec/support/immutable_ids.rb +118 -0
  163. data/spec/support/macros.rb +47 -15
  164. data/spec/support/models/artist.rb +0 -1
  165. data/spec/support/models/band.rb +1 -0
  166. data/spec/support/models/book.rb +1 -0
  167. data/spec/support/models/building.rb +2 -0
  168. data/spec/support/models/cover.rb +10 -0
  169. data/spec/support/models/product.rb +1 -0
  170. data.tar.gz.sig +0 -0
  171. metadata +686 -650
  172. metadata.gz.sig +0 -0
  173. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
  174. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -60
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53bba3a9611a89eaf77478beacbf4a8a3c6751503ecf1919407c7af05e134af0
4
- data.tar.gz: ebe8a6705c4c035e99720d1a37e8103948aa1cb61a66ab42b0d426dd7e10c135
3
+ metadata.gz: 1f5f0b81e26dba41d786804bd1213f2c05c4594ca9e05d0f62417fc15da6532e
4
+ data.tar.gz: c44f03a981d2fc648822718522e2ee7e8db6fa3fec01764eb09d77a4183a3559
5
5
  SHA512:
6
- metadata.gz: 15c3ecad78d34f2bdc3967042c0175b639d813aa44bcb2e6a5aa4ee5ec6d3adcb13e428accefb0edfa6b7dab59710829194e00cc17cb0f38ff5673957c97e6ce
7
- data.tar.gz: ba5f2a0a8cd2ddc48650d9e7b67c162d4071f254ea9de03070308a411aeda8db2ac40c3a548d9543bed2bad637aa001e2a4ed0fe039cb380a30a69d6b79164fd
6
+ metadata.gz: bafd2e708f204e23b0e277df74f897d19a83f059eb34bff3b636231f6e76a83176a45ea1b49586bff52c44bc3a526bd0d988cec3441bc469514035ad0acc7272
7
+ data.tar.gz: 59e6b77e3e03d94cb82fd2aad20c3951cbcc9f0872138ae76f6837986aad641cce339d5d51b8122047b5732266883708f847a7bd23c0ed2fe7bf8e19e834e045
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -63,7 +63,7 @@ For instructions on upgrading to newer versions, visit
63
63
 
64
64
  * Mongoid now uses the official Mongo Ruby Driver 2.x instead of Moped.
65
65
 
66
- * Most driver specific configuration options have changed, please see [here](http://docs.mongodb.org/ecosystem/tutorial/ruby-driver-tutorial/#ruby-options) for the new options.
66
+ * Most driver specific configuration options have changed, please see [here](https://www.mongodb.com/docs/ecosystem/tutorial/ruby-driver-tutorial/#ruby-options) for the new options.
67
67
 
68
68
  * All references to `session` are now replaced with `client`. This includes the mongoid.yml configuration, `store_in` options, and all exceptions and modules with `Session` in the name.
69
69
 
@@ -872,8 +872,8 @@ child elements.
872
872
  handling of validations. (Gerad Suyderhoud)
873
873
 
874
874
  * \#2443 `expire_after_seconds` is now a valid index option
875
- (http://docs.mongodb.org/manual/core/indexes/#ttl-indexes,
876
- http://docs.mongodb.org/manual/tutorial/expire-data/).
875
+ (https://www.mongodb.com/docs/manual/core/indexes/#ttl-indexes,
876
+ https://www.mongodb.com/docs/manual/tutorial/expire-data/).
877
877
 
878
878
  class Event
879
879
  include Mongoid::Document
data/README.md CHANGED
@@ -8,11 +8,11 @@ Mongoid is an ODM (Object-Document Mapper) framework for MongoDB in Ruby.
8
8
  Documentation
9
9
  -------------
10
10
 
11
- Mongoid has [extensive user documentation](https://docs.mongodb.com/mongoid/current/).
12
- [API documentation](https://docs.mongodb.com/mongoid/current/api/) is also available.
11
+ Mongoid has [extensive user documentation](https://www.mongodb.com/docs/mongoid/current/).
12
+ [API documentation](https://www.mongodb.com/docs/mongoid/current/api/) is also available.
13
13
 
14
14
  Mongoid is built on top of the MongoDB Ruby driver which has
15
- [its own user documentation](https://docs.mongodb.com/ruby-driver/current/).
15
+ [its own user documentation](https://www.mongodb.com/docs/ruby-driver/current/).
16
16
 
17
17
  Compatibility
18
18
  -------------
data/Rakefile CHANGED
@@ -11,15 +11,6 @@ $: << File.join(ROOT, 'spec/shared/lib')
11
11
  require "rake"
12
12
  require "rspec/core/rake_task"
13
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
14
 
24
15
  $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
25
16
  require "mongoid/version"
@@ -112,19 +103,3 @@ namespace :release do
112
103
  end
113
104
  end
114
105
  end
115
-
116
- desc 'Verifies that all built gems in pkg/ are valid'
117
- task :verify do
118
- gems = Dir['pkg/*.gem']
119
- if gems.empty?
120
- puts 'There are no gems in pkg/ to verify'
121
- else
122
- gems.each do |gem|
123
- if signed_gem?(gem)
124
- puts "#{gem} is signed"
125
- else
126
- abort "#{gem} is not signed"
127
- end
128
- end
129
- end
130
- end
@@ -31,6 +31,17 @@ en:
31
31
  since the document did not actually get saved."
32
32
  resolution: "Double check all before callbacks to make sure they are
33
33
  not unintentionally returning false."
34
+ create_collection_failure:
35
+ message: "Cannot create collection %{collection_name}
36
+ with options %{collection_options}. The following error was raised:
37
+ %{error}."
38
+ summary: "The server rejected createCollection command with given collection
39
+ options. This may happen when some of the options are invalid, or not
40
+ supported by your version of the server."
41
+ resolution: "Double check that collection options for the collection
42
+ %{collection_name} are valid. Consult with Ruby driver documentation
43
+ and MongoDB documentation if the desired options are supported by
44
+ your version of the server."
34
45
  criteria_argument_required:
35
46
  message: "Calling Criteria methods with nil arguments is not allowed."
36
47
  summary: "Arguments to Criteria methods cannot be nil, and most
@@ -86,11 +97,24 @@ en:
86
97
  resolution: "Search for an id/shard key that is in the database or set
87
98
  the Mongoid.raise_not_found_error configuration option to false,
88
99
  which will cause nil to be returned instead of raising this error."
100
+ drop_collection_failure:
101
+ message: "Cannot drop collection %{collection_name}."
102
+ summary: "Mongoid tried to drop collection %{collection_name}, but the
103
+ collection still exists in the database."
104
+ resolution: "Try to drop the collection manually using Ruby driver or
105
+ mongo shell."
89
106
  empty_config_file:
90
107
  message: "Empty configuration file: %{path}."
91
108
  summary: "Your mongoid.yml configuration file appears to be empty."
92
109
  resolution: "Ensure your configuration file contains the correct contents.
93
- Refer to: https://docs.mongodb.com/mongoid/current/reference/configuration/"
110
+ Refer to: https://www.mongodb.com/docs/mongoid/current/reference/configuration/"
111
+ immutable_attribute:
112
+ message: "Attempted to change the immutable attribute '%{name}' with
113
+ the value: %{value}."
114
+ summary: "Immutable attributes can only have values set when the
115
+ document is a new record."
116
+ resolution: "Do not attempt to update the value of '%{name}' after
117
+ the document is persisted."
94
118
  invalid_collection:
95
119
  message: "Access to the collection for %{klass} is not allowed."
96
120
  summary: "%{klass}.collection was called, and %{klass} is an embedded
@@ -105,12 +129,20 @@ en:
105
129
  A collation option is only supported if the query is executed on a MongoDB server
106
130
  with version >= 3.4."
107
131
  resolution: "Remove the collation option from the query."
132
+ invalid_async_query_executor:
133
+ message: "Invalid async_query_executor option: %{executor}."
134
+ summary: "A invalid async query executor was specified.
135
+ The valid options are: %{options}."
136
+ resolution: "Pick an allowed option or fix the typo. If you were
137
+ expecting the option to be there, please consult the following page
138
+ with respect to Mongoid's configuration:\n\n
139
+ \_\_https://www.mongodb.com/docs/mongoid/current/reference/configuration/#mongoid-configuration-options"
108
140
  invalid_config_file:
109
141
  message: "Invalid configuration file: %{path}."
110
142
  summary: "Your mongoid.yml configuration file does not contain the
111
143
  correct file structure."
112
144
  resolution: "Ensure your configuration file contains the correct contents.
113
- Refer to: https://docs.mongodb.com/mongoid/current/reference/configuration/"
145
+ Refer to: https://www.mongodb.com/docs/mongoid/current/reference/configuration/"
114
146
  invalid_config_option:
115
147
  message: "Invalid configuration option: %{name}."
116
148
  summary: "A invalid configuration option was provided in your
@@ -197,14 +229,21 @@ en:
197
229
  \_\_\_\_field :%{name}, %{option}: true\n
198
230
  \_\_end\n\n
199
231
  Refer to:
200
- https://docs.mongodb.com/mongoid/current/reference/fields/#custom-field-options"
232
+ https://www.mongodb.com/docs/mongoid/current/reference/fields/#custom-field-options"
201
233
  invalid_field_type:
202
234
  message: "Invalid field type %{type_inspection} for field '%{field}' on model '%{klass}'."
203
235
  summary: "Model '%{klass}' defines a field '%{field}' with an unknown type value
204
236
  %{type_inspection}."
205
237
  resolution: "Please provide a valid type value for the field.
206
238
  Refer to:
207
- https://docs.mongodb.com/mongoid/current/reference/fields/#using-symbols-or-strings-instead-of-classes"
239
+ https://www.mongodb.com/docs/mongoid/current/reference/fields/#using-symbols-or-strings-instead-of-classes"
240
+ invalid_global_executor_concurrency:
241
+ message: "Invalid global_executor_concurrency option."
242
+ summary: "You set global_executor_concurrency while async_query_executor
243
+ option is not set to :global_thread_pool. The global_executor_concurrency is
244
+ allowed only for the global thread pool executor."
245
+ resolution: "Set global_executor_concurrency option to :global_thread_pool
246
+ or remove global_executor_concurrency option."
208
247
  invalid_includes:
209
248
  message: "Invalid includes directive: %{klass}.includes(%{args})"
210
249
  summary: "Eager loading in Mongoid only supports providing arguments
@@ -315,7 +354,7 @@ en:
315
354
  invalid_storage_options:
316
355
  message: "Invalid options passed to %{klass}.store_in: %{options}."
317
356
  summary: "The :store_in macro takes only a hash of parameters with
318
- the keys :database, :collection, or :client."
357
+ the keys :database, :collection, :collection_options, or :client."
319
358
  resolution: "Change the options passed to store_in to match the
320
359
  documented API, and ensure all keys in the options hash are
321
360
  symbols.\n\n
@@ -324,12 +363,6 @@ en:
324
363
  \_\_\_\_include Mongoid::Document\n
325
364
  \_\_\_\_store_in collection: 'artists', database: 'music'\n
326
365
  \_\_end\n\n"
327
- invalid_storage_parent:
328
- message: "Invalid store_in call on class %{klass}."
329
- summary: "The :store_in macro can only be called on a base Mongoid Document"
330
- resolution: "Remove the store_in call on class %{klass}, as it will use its
331
- parent store configuration. Or remove the hierarchy extension for this
332
- class."
333
366
  invalid_time:
334
367
  message: "'%{value}' is not a valid Time."
335
368
  summary: "Mongoid tries to serialize the values for Date, DateTime, and
@@ -545,9 +578,8 @@ en:
545
578
  resolution: "Don't define '%{name}' as readonly, or do not attempt
546
579
  to update its value after the document is persisted."
547
580
  readonly_document:
548
- message: "Attempted to persist the readonly document '%{klass}'."
549
- summary: "Documents loaded from the database using #only
550
- cannot be persisted."
581
+ message: "Attempted to persist a readonly document of class '%{klass}'."
582
+ summary: "Documents that are marked readonly cannot be persisted."
551
583
  resolution: "Don't attempt to persist documents that are flagged as
552
584
  readonly."
553
585
  scope_overwrite:
@@ -206,7 +206,7 @@ module Mongoid
206
206
 
207
207
  # Positional projection is specified as "foo.$". In this case the
208
208
  # document that the $ is referring to should be retrieved with all
209
- # fields. See https://docs.mongodb.com/manual/reference/operator/projection/positional/
209
+ # fields. See https://www.mongodb.com/docs/manual/reference/operator/projection/positional/
210
210
  # and https://jira.mongodb.org/browse/MONGOID-4769.
211
211
  if filtered.keys == %w($)
212
212
  filtered = nil
@@ -251,7 +251,7 @@ module Mongoid
251
251
  # @example Parse the args.
252
252
  # doc.parse_args(:name => "Joe")
253
253
  #
254
- # @param [ Array ] args The arguments.
254
+ # @param [ Hash... ] *args The arguments.
255
255
  #
256
256
  # @return [ Array<Hash> ] The attributes and options.
257
257
  def parse_args(*args)
@@ -27,7 +27,7 @@ module Mongoid
27
27
  # @example Parse the args.
28
28
  # doc.parse_args(:name => "Joe")
29
29
  #
30
- # @param [ Array ] args The arguments.
30
+ # @param [ Hash... ] *args The arguments.
31
31
  #
32
32
  # @return [ Array<Hash> ] The attributes and options.
33
33
  def parse_args(*args)
@@ -97,7 +97,7 @@ module Mongoid
97
97
  # @example Batch replace the documents.
98
98
  # batchable.batch_replace([ doc_one, doc_two ])
99
99
  #
100
- # @param [ Array<Document> ] docs The docs to replace with.
100
+ # @param [ Array<Document> | Array<Hash> ] docs The docs to replace with.
101
101
  #
102
102
  # @return [ Array<Hash> ] The inserts.
103
103
  def batch_replace(docs)
@@ -235,7 +235,7 @@ module Mongoid
235
235
  # @example Normalize the docs.
236
236
  # batchable.normalize_docs(docs)
237
237
  #
238
- # @param [ Array<Hash | Document> ] docs The docs to normalize.
238
+ # @param [ Array<Document> | Array<Hash> ] docs The docs to normalize.
239
239
  #
240
240
  # @return [ Array<Document> ] The docs.
241
241
  def normalize_docs(docs)
@@ -15,8 +15,8 @@ module Mongoid
15
15
  # @example Build the document.
16
16
  # Builder.new(meta, attrs).build
17
17
  #
18
- # @param [ Object ] base The object.
19
- # @param [ Object ] object The parent hash or document.
18
+ # @param [ Document ] base The object.
19
+ # @param [ Document | Hash ] object The parent hash or document.
20
20
  # @param [ String ] type Not used in this context.
21
21
  # @param [ Hash ] selected_fields Fields which were retrieved via
22
22
  # #only. If selected_fields are specified, fields not listed in it
@@ -30,7 +30,7 @@ module Mongoid
30
30
  # @example Substitute the new document.
31
31
  # person.name.substitute(new_name)
32
32
  #
33
- # @param [ Document ] replacement A document to replace the target.
33
+ # @param [ Document | Hash ] replacement A document to replace the target.
34
34
  #
35
35
  # @return [ Document | nil ] The association or nil.
36
36
  def substitute(replacement)
@@ -40,6 +40,7 @@ module Mongoid
40
40
  return nil
41
41
  end
42
42
  _base.new_record = true
43
+ replacement = Factory.build(klass, replacement) if replacement.is_a?(::Hash)
43
44
  self._target = replacement
44
45
  bind_one
45
46
  self
@@ -17,8 +17,9 @@ module Mongoid
17
17
  # @example Build the documents.
18
18
  # Builder.new(meta, attrs).build
19
19
  #
20
- # @param [ Object ] base The base object.
21
- # @param [ Object ] object The object to use to build the association.
20
+ # @param [ Document ] base The base object.
21
+ # @param [ Array<Document> | Array<Hash> ] object The object to use
22
+ # to build the association.
22
23
  # @param [ String ] type Not used in this context.
23
24
  # @param [ Hash ] selected_fields Fields which were retrieved via
24
25
  # #only. If selected_fields are specified, fields not listed in it
@@ -19,7 +19,7 @@ module Mongoid
19
19
  # @example Push a document.
20
20
  # person.addresses.push(address)
21
21
  #
22
- # @param [ Document | Array<Document> ] args Any number of documents.
22
+ # @param [ Document... ] *args Any number of documents.
23
23
  def <<(*args)
24
24
  docs = args.flatten
25
25
  return concat(docs) if docs.size > 1
@@ -117,7 +117,7 @@ module Mongoid
117
117
  # @example Use #persisted? inside block to count persisted documents.
118
118
  # person.addresses.count { |a| a.persisted? && a.country == "FR" }
119
119
  #
120
- # @param [ Object | Array<Object> ] args Args to delegate to the target.
120
+ # @param [ Object... ] *args Args to delegate to the target.
121
121
  #
122
122
  # @return [ Integer ] The total number of persisted embedded docs, as
123
123
  # flagged by the #persisted? method.
@@ -252,7 +252,7 @@ module Mongoid
252
252
  # @example Finds the first matching document using a block.
253
253
  # person.addresses.find { |addr| addr.state == 'CA' }
254
254
  #
255
- # @param [ Array<Object> ] args Various arguments.
255
+ # @param [ Object... ] *args Various arguments.
256
256
  # @param [ Proc ] block Optional block to pass.
257
257
  #
258
258
  # @return [ Document | Array<Document> | nil ] A document or matching documents.
@@ -348,7 +348,7 @@ module Mongoid
348
348
  # @example Substitute the association's target.
349
349
  # person.addresses.substitute([ address ])
350
350
  #
351
- # @param [ Array<Document> ] docs The replacement docs.
351
+ # @param [ Array<Document> | Array<Hash> ] docs The replacement docs.
352
352
  #
353
353
  # @return [ Many ] The proxied association.
354
354
  def substitute(docs)
@@ -432,10 +432,10 @@ module Mongoid
432
432
  # If the method exists on the array, use the default proxy behavior.
433
433
  #
434
434
  # @param [ Symbol | String ] name The name of the method.
435
- # @param [ Array ] args The method args
435
+ # @param [ Object... ] *args The method args.
436
436
  # @param [ Proc ] block Optional block to pass.
437
437
  #
438
- # @return [ Criteria, Object ] A Criteria or return value from the target.
438
+ # @return [ Criteria | Object ] A Criteria or return value from the target.
439
439
  ruby2_keywords def method_missing(name, *args, &block)
440
440
  return super if _target.respond_to?(name)
441
441
  klass.send(:with_scope, criteria) do
@@ -17,7 +17,7 @@ module Mongoid
17
17
  # Builder.new(meta, attrs).build
18
18
  #
19
19
  # @param [ Document ] base The document this association hangs off of.
20
- # @param [ Document ] object The related document.
20
+ # @param [ Document | Hash ] object The related document.
21
21
  # @param [ String ] _type Not used in this context.
22
22
  # @param [ Hash ] selected_fields Fields which were retrieved via
23
23
  # #only. If selected_fields are specified, fields not listed in it
@@ -43,7 +43,7 @@ module Mongoid
43
43
  # @example Substitute the new document.
44
44
  # person.name.substitute(new_name)
45
45
  #
46
- # @param [ Document ] replacement A document to replace the target.
46
+ # @param [ Document | Hash ] replacement A document to replace the target.
47
47
  #
48
48
  # @return [ Document | nil ] The association or nil.
49
49
  def substitute(replacement)
@@ -32,6 +32,8 @@ module Mongoid
32
32
  parent.send(association.setter, Factory.build(@class_name, attributes))
33
33
  elsif delete?
34
34
  parent.send(association.setter, nil)
35
+ else
36
+ check_for_id_violation!
35
37
  end
36
38
  end
37
39
 
@@ -54,6 +56,17 @@ module Mongoid
54
56
 
55
57
  private
56
58
 
59
+ # Extracts and converts the id to the expected type.
60
+ #
61
+ # @return [ BSON::ObjectId | String | Object | nil ] The converted id,
62
+ # or nil if no id is present in the attributes hash.
63
+ def extracted_id
64
+ @extracted_id ||= begin
65
+ id = association.klass.extract_id_field(attributes)
66
+ convert_id(existing.class, id)
67
+ end
68
+ end
69
+
57
70
  # Is the id in the attributes acceptable for allowing an update to
58
71
  # the existing association?
59
72
  #
@@ -64,8 +77,7 @@ module Mongoid
64
77
  #
65
78
  # @return [ true | false ] If the id part of the logic will allow an update.
66
79
  def acceptable_id?
67
- id = association.klass.extract_id_field(attributes)
68
- id = convert_id(existing.class, id)
80
+ id = extracted_id
69
81
  existing._id == id || id.nil? || (existing._id != id && update_only?)
70
82
  end
71
83
 
@@ -110,6 +122,32 @@ module Mongoid
110
122
  def update?
111
123
  existing && !destroyable? && acceptable_id?
112
124
  end
125
+
126
+ # Checks to see if the _id attribute (which is supposed to be
127
+ # immutable) is being asked to change. If so, raise an exception.
128
+ #
129
+ # If Mongoid::Config.immutable_ids is false, this will do nothing,
130
+ # and the update operation will fail silently.
131
+ #
132
+ # @raise [ Errors::ImmutableAttribute ] if _id has changed, and
133
+ # the document has been persisted.
134
+ def check_for_id_violation!
135
+ # look for the basic criteria of an update (see #update?)
136
+ return unless existing&.persisted? && !destroyable?
137
+
138
+ # if the id is either absent, or if it equals the existing record's
139
+ # id, there is no immutability violation.
140
+ id = extracted_id
141
+ return if existing._id == id || id.nil?
142
+
143
+ # otherwise, an attempt has been made to set the _id of an existing,
144
+ # persisted document.
145
+ if Mongoid::Config.immutable_ids
146
+ raise Errors::ImmutableAttribute.new(:_id, id)
147
+ else
148
+ Mongoid::Warnings.warn_mutable_ids
149
+ end
150
+ end
113
151
  end
114
152
  end
115
153
  end
@@ -118,7 +118,7 @@ module Mongoid
118
118
  # to the target of the proxy. This can be overridden in special cases.
119
119
  #
120
120
  # @param [ String | Symbol ] name The name of the method.
121
- # @param [ Array ] args The arguments passed to the method.
121
+ # @param [ Object... ] *args The arguments passed to the method.
122
122
  ruby2_keywords def method_missing(name, *args, &block)
123
123
  _target.send(name, *args, &block)
124
124
  end
@@ -13,7 +13,7 @@ module Mongoid
13
13
  # @example Reset the given counter cache
14
14
  # post.reset_counters(:comments)
15
15
  #
16
- # @param [ Symbol | Array ] counters One or more counter caches to reset
16
+ # @param [ Symbol... ] *counters One or more counter caches to reset.
17
17
  def reset_counters(*counters)
18
18
  self.class.with(persistence_context) do |_class|
19
19
  _class.reset_counters(self, *counters)
@@ -30,7 +30,7 @@ module Mongoid
30
30
  # Post.reset_counters('50e0edd97c71c17ea9000001', :comments)
31
31
  #
32
32
  # @param [ String ] id The id of the object that will be reset.
33
- # @param [ Symbol | Array ] counters One or more counter caches to reset
33
+ # @param [ Symbol... ] *counters One or more counter caches to reset.
34
34
  def reset_counters(id, *counters)
35
35
  document = id.is_a?(Document) ? id : find(id)
36
36
  counters.each do |name|
@@ -21,7 +21,7 @@ module Mongoid
21
21
  # @example Concat with other documents.
22
22
  # person.posts.concat([ post_one, post_two ])
23
23
  #
24
- # @param [ Document | Array<Document> ] args Any number of documents.
24
+ # @param [ Document... ] *args Any number of documents.
25
25
  #
26
26
  # @return [ Array<Document> ] The loaded docs.
27
27
  def <<(*args)
@@ -215,13 +215,13 @@ module Mongoid
215
215
  # completely depending on whether it is iterated to completion.
216
216
  #
217
217
  # This method can take a parameter and a block. The behavior with
218
- # either the paramater or the block is delegated to the standard
218
+ # either the parameter or the block is delegated to the standard
219
219
  # library Enumerable module.
220
220
  #
221
221
  # Note that when Enumerable's any? method is invoked with both
222
222
  # a block and a pattern, it only uses the pattern.
223
223
  #
224
- # @param [ Object ] condition The condition that documents
224
+ # @param [ Object... ] *args The condition that documents
225
225
  # must satisfy. See Enumerable documentation for details.
226
226
  #
227
227
  # @return [ true | false ] If the association has any documents.
@@ -25,7 +25,7 @@ module Mongoid
25
25
  # @example Concat with other documents.
26
26
  # person.posts.concat([ post_one, post_two ])
27
27
  #
28
- # @param [ Document | Array<Document> ] args Any number of documents.
28
+ # @param [ Document... ] *args Any number of documents.
29
29
  #
30
30
  # @return [ Array<Document> ] The loaded docs.
31
31
  def <<(*args)
@@ -203,7 +203,7 @@ module Mongoid
203
203
  # @note This will keep matching documents in memory for iteration
204
204
  # later.
205
205
  #
206
- # @param [ Object | Array<Object> ] *args The ids.
206
+ # @param [ [ Object | Array<Object> ]... ] *args The ids.
207
207
  # @param [ Proc ] block Optional block to pass.
208
208
  #
209
209
  # @return [ Document | Array<Document> | nil ] A document or matching documents.
@@ -418,7 +418,7 @@ module Mongoid
418
418
  # If the method exists on the array, use the default proxy behavior.
419
419
  #
420
420
  # @param [ Symbol | String ] name The name of the method.
421
- # @param [ Array ] args The method args
421
+ # @param [ Object... ] *args The method args
422
422
  # @param [ Proc ] block Optional block to pass.
423
423
  #
424
424
  # @return [ Criteria | Object ] A Criteria or return value from the target.
@@ -25,7 +25,7 @@ module Mongoid
25
25
  # @example Find multiple association metadata by macro.
26
26
  # person.reflect_on_all_associations(:embeds_many)
27
27
  #
28
- # @param [ Array<Symbol> ] macros The association macros.
28
+ # @param [ Symbol... ] *macros The association macros.
29
29
  #
30
30
  # @return [ Array<Association> ] The matching association metadata.
31
31
  def reflect_on_all_association(*macros)
@@ -51,7 +51,7 @@ module Mongoid
51
51
  # @example Find multiple association metadata by macro.
52
52
  # Person.reflect_on_all_associations(:embeds_many)
53
53
  #
54
- # @param [ Array<Symbol> ] macros The association macros.
54
+ # @param [ Symbol... ] *macros The association macros.
55
55
  #
56
56
  # @return [ Array<Association> ] The matching association metadata.
57
57
  def reflect_on_all_associations(*macros)
@@ -311,13 +311,6 @@ module Mongoid
311
311
 
312
312
  private
313
313
 
314
- # Clears all pending atomic updates.
315
- def reset_atomic_updates!
316
- Atomic::UPDATES.each do |update|
317
- send(update).clear
318
- end
319
- end
320
-
321
314
  # Generates the atomic updates in the correct order.
322
315
  #
323
316
  # @example Generate the updates.
@@ -115,7 +115,7 @@ module Mongoid
115
115
  # document.method_missing(:test)
116
116
  #
117
117
  # @param [ String | Symbol ] name The name of the method.
118
- # @param [ Array ] args The arguments to the method.
118
+ # @param [ Object... ] *args The arguments to the method.
119
119
  #
120
120
  # @return [ Object ] The result of the method call.
121
121
  def method_missing(name, *args)
@@ -33,8 +33,8 @@ module Mongoid
33
33
  # accepts_nested_attributes_for :addresses, :game, :posts
34
34
  # end
35
35
  #
36
- # @param [ Array<Symbol> | Hash ] args A list of association names, followed
37
- # by a hash of options.
36
+ # @param [ Symbol..., Hash ] *args A list of association names, followed
37
+ # by an optional hash of options.
38
38
  #
39
39
  # @option *args [ true | false ] :allow_destroy Can deletion occur?
40
40
  # @option *args [ Proc | Symbol ] :reject_if Block or symbol pointing
@@ -6,7 +6,7 @@ module Mongoid
6
6
  # This module defines projection helpers.
7
7
  #
8
8
  # Projection rules are rather non-trivial. See
9
- # https://docs.mongodb.com/manual/reference/method/db.collection.find/#find-projection
9
+ # https://www.mongodb.com/docs/manual/reference/method/db.collection.find/#find-projection
10
10
  # for server documentation.
11
11
  # 4.4 server (and presumably all older ones) requires that a projection
12
12
  # for content fields is either exclusionary or inclusionary, i.e. one
@@ -61,7 +61,7 @@ module Mongoid
61
61
  # attr_readonly :name, :genre
62
62
  # end
63
63
  #
64
- # @param [ Array<Symbol> ] names The names of the fields.
64
+ # @param [ Symbol... ] *names The names of the fields.
65
65
  def attr_readonly(*names)
66
66
  names.each do |name|
67
67
  readonly_attributes << database_field_name(name)
@@ -177,8 +177,14 @@ module Mongoid
177
177
  attribute_will_change!(field_name)
178
178
  end
179
179
  if localized
180
- attributes[field_name] ||= {}
181
- attributes[field_name].merge!(typed_value)
180
+ present = fields[field_name].try(:localize_present?)
181
+ loc_key, loc_val = typed_value.first
182
+ if present && loc_val.blank?
183
+ attributes[field_name]&.delete(loc_key)
184
+ else
185
+ attributes[field_name] ||= {}
186
+ attributes[field_name].merge!(typed_value)
187
+ end
182
188
  else
183
189
  attributes[field_name] = typed_value
184
190
  end