mongoid 7.6.0 → 8.0.1

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 (313) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -0
  3. data/README.md +3 -3
  4. data/Rakefile +21 -85
  5. data/lib/config/locales/en.yml +46 -30
  6. data/lib/mongoid/association/accessors.rb +32 -3
  7. data/lib/mongoid/association/bindable.rb +48 -0
  8. data/lib/mongoid/association/builders.rb +4 -2
  9. data/lib/mongoid/association/eager_loadable.rb +29 -7
  10. data/lib/mongoid/association/embedded/batchable.rb +28 -5
  11. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  12. data/lib/mongoid/association/embedded/embedded_in.rb +2 -1
  13. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  14. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +1 -1
  15. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +40 -18
  16. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +18 -4
  17. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +21 -2
  18. data/lib/mongoid/association/macros.rb +2 -1
  19. data/lib/mongoid/association/many.rb +5 -0
  20. data/lib/mongoid/association/nested/many.rb +2 -1
  21. data/lib/mongoid/association/proxy.rb +12 -0
  22. data/lib/mongoid/association/referenced/auto_save.rb +3 -2
  23. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  24. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  25. data/lib/mongoid/association/referenced/belongs_to.rb +1 -1
  26. data/lib/mongoid/association/referenced/counter_cache.rb +8 -8
  27. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +64 -11
  28. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +4 -1
  29. data/lib/mongoid/association/referenced/has_many/enumerable.rb +10 -18
  30. data/lib/mongoid/association/referenced/has_many/proxy.rb +12 -9
  31. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  32. data/lib/mongoid/association/referenced/has_one/proxy.rb +8 -11
  33. data/lib/mongoid/association/referenced/syncable.rb +2 -2
  34. data/lib/mongoid/association/relatable.rb +38 -4
  35. data/lib/mongoid/attributes/processing.rb +9 -2
  36. data/lib/mongoid/attributes.rb +30 -27
  37. data/lib/mongoid/cacheable.rb +2 -2
  38. data/lib/mongoid/changeable.rb +37 -2
  39. data/lib/mongoid/clients/options.rb +4 -0
  40. data/lib/mongoid/clients/sessions.rb +2 -14
  41. data/lib/mongoid/config.rb +15 -11
  42. data/lib/mongoid/contextual/aggregable/memory.rb +23 -15
  43. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  44. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  45. data/lib/mongoid/contextual/memory.rb +55 -28
  46. data/lib/mongoid/contextual/mongo.rb +173 -287
  47. data/lib/mongoid/contextual/none.rb +33 -15
  48. data/lib/mongoid/copyable.rb +32 -8
  49. data/lib/mongoid/criteria/includable.rb +24 -20
  50. data/lib/mongoid/criteria/marshalable.rb +10 -2
  51. data/lib/mongoid/criteria/queryable/extensions/array.rb +2 -15
  52. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  53. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  54. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  55. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  56. data/lib/mongoid/criteria/queryable/extensions/hash.rb +0 -16
  57. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  58. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  59. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  60. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +1 -1
  61. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +3 -1
  62. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  63. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  64. data/lib/mongoid/criteria/queryable/optional.rb +3 -9
  65. data/lib/mongoid/criteria/queryable/options.rb +1 -1
  66. data/lib/mongoid/criteria/queryable/selectable.rb +2 -24
  67. data/lib/mongoid/criteria/queryable/selector.rb +90 -5
  68. data/lib/mongoid/criteria/queryable/smash.rb +39 -6
  69. data/lib/mongoid/criteria/queryable/storable.rb +1 -1
  70. data/lib/mongoid/criteria/queryable.rb +11 -6
  71. data/lib/mongoid/criteria.rb +1 -28
  72. data/lib/mongoid/deprecable.rb +36 -0
  73. data/lib/mongoid/deprecation.rb +25 -0
  74. data/lib/mongoid/document.rb +88 -33
  75. data/lib/mongoid/equality.rb +4 -4
  76. data/lib/mongoid/errors/document_not_found.rb +6 -2
  77. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  78. data/lib/mongoid/errors/invalid_field.rb +5 -1
  79. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  80. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  81. data/lib/mongoid/errors.rb +2 -2
  82. data/lib/mongoid/extensions/array.rb +8 -6
  83. data/lib/mongoid/extensions/big_decimal.rb +29 -10
  84. data/lib/mongoid/extensions/binary.rb +42 -0
  85. data/lib/mongoid/extensions/boolean.rb +8 -2
  86. data/lib/mongoid/extensions/date.rb +26 -20
  87. data/lib/mongoid/extensions/date_time.rb +1 -1
  88. data/lib/mongoid/extensions/float.rb +4 -5
  89. data/lib/mongoid/extensions/hash.rb +12 -5
  90. data/lib/mongoid/extensions/integer.rb +4 -5
  91. data/lib/mongoid/extensions/object.rb +2 -0
  92. data/lib/mongoid/extensions/range.rb +41 -10
  93. data/lib/mongoid/extensions/regexp.rb +11 -4
  94. data/lib/mongoid/extensions/set.rb +11 -4
  95. data/lib/mongoid/extensions/string.rb +2 -13
  96. data/lib/mongoid/extensions/symbol.rb +3 -14
  97. data/lib/mongoid/extensions/time.rb +27 -16
  98. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  99. data/lib/mongoid/extensions.rb +1 -0
  100. data/lib/mongoid/factory.rb +42 -7
  101. data/lib/mongoid/fields/foreign_key.rb +7 -0
  102. data/lib/mongoid/fields/validators/macro.rb +3 -9
  103. data/lib/mongoid/fields.rb +49 -7
  104. data/lib/mongoid/findable.rb +21 -16
  105. data/lib/mongoid/indexable/specification.rb +1 -1
  106. data/lib/mongoid/indexable/validators/options.rb +4 -1
  107. data/lib/mongoid/interceptable.rb +69 -9
  108. data/lib/mongoid/persistable/creatable.rb +14 -5
  109. data/lib/mongoid/persistable/updatable.rb +12 -5
  110. data/lib/mongoid/persistence_context.rb +8 -42
  111. data/lib/mongoid/query_cache.rb +6 -258
  112. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  113. data/lib/mongoid/reloadable.rb +7 -3
  114. data/lib/mongoid/scopable.rb +9 -11
  115. data/lib/mongoid/selectable.rb +1 -2
  116. data/lib/mongoid/shardable.rb +11 -35
  117. data/lib/mongoid/stateful.rb +27 -1
  118. data/lib/mongoid/timestamps/created.rb +1 -1
  119. data/lib/mongoid/timestamps/updated.rb +1 -1
  120. data/lib/mongoid/touchable.rb +2 -3
  121. data/lib/mongoid/traversable.rb +1 -0
  122. data/lib/mongoid/validatable/uniqueness.rb +2 -1
  123. data/lib/mongoid/version.rb +1 -5
  124. data/lib/mongoid/warnings.rb +3 -4
  125. data/lib/mongoid.rb +1 -0
  126. data/spec/config/mongoid.yml +16 -0
  127. data/spec/integration/app_spec.rb +8 -12
  128. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  129. data/spec/integration/associations/embedded_spec.rb +15 -0
  130. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  131. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  132. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  133. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  134. data/spec/integration/associations/has_one_spec.rb +97 -1
  135. data/spec/integration/associations/scope_option_spec.rb +1 -1
  136. data/spec/integration/callbacks_models.rb +95 -1
  137. data/spec/integration/callbacks_spec.rb +226 -4
  138. data/spec/integration/criteria/range_spec.rb +95 -1
  139. data/spec/integration/discriminator_key_spec.rb +115 -76
  140. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  141. data/spec/integration/i18n_fallbacks_spec.rb +1 -15
  142. data/spec/integration/matcher_examples_spec.rb +20 -13
  143. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  144. data/spec/integration/matcher_operator_spec.rb +3 -5
  145. data/spec/integration/persistence/range_field_spec.rb +350 -0
  146. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  147. data/spec/mongoid/association/depending_spec.rb +9 -9
  148. data/spec/mongoid/association/eager_spec.rb +2 -1
  149. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  150. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  151. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +69 -9
  152. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  153. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +198 -8
  154. data/spec/mongoid/association/embedded/embeds_many_models.rb +36 -0
  155. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
  156. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  157. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  158. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  159. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  160. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  161. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  162. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  163. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  164. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -2
  165. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +38 -5
  166. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  167. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  168. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  169. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2 -56
  170. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +62 -13
  171. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  172. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  173. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  174. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  175. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  176. data/spec/mongoid/association/syncable_spec.rb +14 -0
  177. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  178. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  179. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  180. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  181. data/spec/mongoid/attributes_spec.rb +480 -27
  182. data/spec/mongoid/cacheable_spec.rb +3 -3
  183. data/spec/mongoid/changeable_spec.rb +130 -13
  184. data/spec/mongoid/clients/factory_spec.rb +23 -30
  185. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  186. data/spec/mongoid/clients_spec.rb +2 -2
  187. data/spec/mongoid/config_spec.rb +52 -15
  188. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  189. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  190. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  191. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  192. data/spec/mongoid/contextual/memory_spec.rb +521 -14
  193. data/spec/mongoid/contextual/mongo_spec.rb +566 -426
  194. data/spec/mongoid/contextual/none_spec.rb +11 -19
  195. data/spec/mongoid/copyable_spec.rb +451 -2
  196. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  197. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  198. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  199. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  200. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  201. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  202. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +1 -2
  203. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  204. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  205. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +1 -2
  206. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  207. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  208. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  209. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  210. data/spec/mongoid/criteria/queryable/optional_spec.rb +0 -484
  211. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  212. data/spec/mongoid/criteria/queryable/selectable_spec.rb +77 -85
  213. data/spec/mongoid/criteria/queryable/selector_spec.rb +16 -77
  214. data/spec/mongoid/criteria/queryable/storable_spec.rb +0 -72
  215. data/spec/mongoid/criteria_spec.rb +469 -1201
  216. data/spec/mongoid/document_fields_spec.rb +173 -24
  217. data/spec/mongoid/document_spec.rb +32 -41
  218. data/spec/mongoid/equality_spec.rb +12 -12
  219. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  220. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  221. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  222. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  223. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  224. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  225. data/spec/mongoid/extensions/array_spec.rb +16 -2
  226. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  227. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  228. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  229. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  230. data/spec/mongoid/extensions/date_spec.rb +71 -1
  231. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  232. data/spec/mongoid/extensions/float_spec.rb +48 -76
  233. data/spec/mongoid/extensions/hash_spec.rb +30 -0
  234. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  235. data/spec/mongoid/extensions/range_spec.rb +255 -54
  236. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  237. data/spec/mongoid/extensions/set_spec.rb +106 -0
  238. data/spec/mongoid/extensions/string_spec.rb +53 -25
  239. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  240. data/spec/mongoid/extensions/time_spec.rb +634 -66
  241. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  242. data/spec/mongoid/factory_spec.rb +61 -1
  243. data/spec/mongoid/fields_spec.rb +321 -50
  244. data/spec/mongoid/findable_spec.rb +64 -29
  245. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  246. data/spec/mongoid/indexable_spec.rb +16 -19
  247. data/spec/mongoid/interceptable_spec.rb +584 -5
  248. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  249. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  250. data/spec/mongoid/mongoizable_spec.rb +285 -0
  251. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  252. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  253. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  254. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  255. data/spec/mongoid/persistence_context_spec.rb +24 -0
  256. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  257. data/spec/mongoid/query_cache_spec.rb +1 -156
  258. data/spec/mongoid/reloadable_spec.rb +35 -2
  259. data/spec/mongoid/scopable_spec.rb +36 -34
  260. data/spec/mongoid/serializable_spec.rb +14 -7
  261. data/spec/mongoid/shardable_models.rb +0 -14
  262. data/spec/mongoid/shardable_spec.rb +61 -153
  263. data/spec/mongoid/stateful_spec.rb +28 -0
  264. data/spec/mongoid/timestamps_spec.rb +390 -0
  265. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  266. data/spec/mongoid/touchable_spec.rb +116 -0
  267. data/spec/mongoid/touchable_spec_models.rb +12 -8
  268. data/spec/mongoid/traversable_spec.rb +4 -11
  269. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  270. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  271. data/spec/mongoid/warnings_spec.rb +35 -0
  272. data/spec/mongoid_spec.rb +1 -7
  273. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  274. data/spec/rails/mongoid_spec.rb +4 -16
  275. data/spec/shared/lib/mrss/docker_runner.rb +1 -8
  276. data/spec/shared/lib/mrss/event_subscriber.rb +5 -15
  277. data/spec/shared/lib/mrss/lite_constraints.rb +2 -10
  278. data/spec/shared/lib/mrss/server_version_registry.rb +24 -17
  279. data/spec/shared/lib/mrss/spec_organizer.rb +3 -32
  280. data/spec/shared/lib/mrss/utils.rb +6 -28
  281. data/spec/shared/share/Dockerfile.erb +107 -33
  282. data/spec/shared/shlib/distro.sh +0 -10
  283. data/spec/shared/shlib/server.sh +33 -64
  284. data/spec/shared/shlib/set_env.sh +71 -12
  285. data/spec/support/constraints.rb +24 -0
  286. data/spec/support/expectations.rb +17 -20
  287. data/spec/support/macros.rb +30 -0
  288. data/spec/support/models/augmentation.rb +12 -0
  289. data/spec/support/models/band.rb +3 -0
  290. data/spec/support/models/catalog.rb +24 -0
  291. data/spec/support/models/circus.rb +3 -0
  292. data/spec/support/models/fanatic.rb +8 -0
  293. data/spec/support/models/implant.rb +9 -0
  294. data/spec/support/models/label.rb +2 -0
  295. data/spec/support/models/passport.rb +9 -0
  296. data/spec/support/models/person.rb +1 -0
  297. data/spec/support/models/player.rb +2 -0
  298. data/spec/support/models/powerup.rb +12 -0
  299. data/spec/support/models/registry.rb +1 -0
  300. data/spec/support/models/school.rb +14 -0
  301. data/spec/support/models/shield.rb +18 -0
  302. data/spec/support/models/student.rb +14 -0
  303. data/spec/support/models/weapon.rb +12 -0
  304. data.tar.gz.sig +0 -0
  305. metadata +695 -641
  306. metadata.gz.sig +0 -0
  307. data/lib/mongoid/errors/eager_load.rb +0 -23
  308. data/lib/mongoid/errors/invalid_value.rb +0 -17
  309. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
  310. data/spec/shared/CANDIDATE.md +0 -28
  311. data/spec/shared/lib/mrss/release/candidate.rb +0 -281
  312. data/spec/shared/lib/mrss/release/product_data.rb +0 -144
  313. data/spec/shared/lib/tasks/candidate.rake +0 -64
@@ -103,4 +103,116 @@ describe Mongoid::Association::Embedded::EmbedsMany::Buildable do
103
103
  end
104
104
  end
105
105
  end
106
+
107
+ context 'when the object is already associated with another object' do
108
+
109
+ context "when using <<" do
110
+
111
+ let(:person1) do
112
+ Person.new
113
+ end
114
+
115
+ let(:person2) do
116
+ Person.new
117
+ end
118
+
119
+ let(:appointment) do
120
+ Appointment.new
121
+ end
122
+
123
+ before do
124
+ person1.appointments << appointment
125
+ person2.appointments << appointment
126
+ end
127
+
128
+ it 'clears the object of its previous association' do
129
+ expect(person1.appointments).to eq([])
130
+ expect(person2.appointments).to eq([appointment])
131
+ end
132
+ end
133
+
134
+ context "when using concat" do
135
+
136
+ let(:person1) do
137
+ Person.new
138
+ end
139
+
140
+ let(:person2) do
141
+ Person.new
142
+ end
143
+
144
+ let(:appointment) do
145
+ Appointment.new
146
+ end
147
+
148
+ before do
149
+ person1.appointments.concat([appointment])
150
+ person2.appointments.concat([appointment])
151
+ end
152
+
153
+ it 'clears the object of its previous association' do
154
+ expect(person1.appointments).to eq([])
155
+ expect(person2.appointments).to eq([appointment])
156
+ end
157
+ end
158
+
159
+ context "when using =" do
160
+
161
+ let(:person1) do
162
+ Person.new
163
+ end
164
+
165
+ let(:person2) do
166
+ Person.new
167
+ end
168
+
169
+ let(:appointment) do
170
+ Appointment.new
171
+ end
172
+
173
+ let(:apts) { [ appointment ] }
174
+
175
+ before do
176
+ person1.appointments = apts
177
+ person2.appointments = apts
178
+ expect(apts).to eq([ appointment ])
179
+ end
180
+
181
+ it 'clears the object of its previous association' do
182
+ expect(person1.appointments).to eq([])
183
+ expect(person2.appointments).to eq([appointment])
184
+ end
185
+ end
186
+
187
+ context "when using = on the same document twice" do
188
+
189
+ let(:person1) do
190
+ Person.new
191
+ end
192
+
193
+ let(:person2) do
194
+ Person.new
195
+ end
196
+
197
+ let(:appointment1) do
198
+ Appointment.new
199
+ end
200
+
201
+ let(:appointment2) do
202
+ Appointment.new
203
+ end
204
+
205
+ let(:apts) { [ appointment1, appointment2 ] }
206
+
207
+ before do
208
+ person1.appointments = apts
209
+ person1.appointments = person1.appointments.reverse
210
+ expect(apts).to eq([ appointment1, appointment2 ])
211
+ end
212
+
213
+ it 'clears the object of its previous association' do
214
+ expect(person1.appointments).to eq([ appointment2, appointment1 ])
215
+ end
216
+ end
217
+ end
106
218
  end
@@ -2210,6 +2210,79 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
2210
2210
  end
2211
2211
  end
2212
2212
  end
2213
+
2214
+ context "when modifying the document beforehand" do
2215
+ let(:parent) { EmmParent.new }
2216
+
2217
+ before do
2218
+
2219
+ parent.blocks << EmmBlock.new(name: 'test', children: [size: 1, order: 1])
2220
+ parent.save!
2221
+
2222
+ parent.blocks[0].children[0].assign_attributes(size: 2)
2223
+
2224
+ parent.blocks.destroy_all(:name => 'test')
2225
+ end
2226
+
2227
+ it "deletes the correct document in the database" do
2228
+ expect(parent.reload.blocks.length).to eq(0)
2229
+ end
2230
+ end
2231
+
2232
+ context "when nil _id" do
2233
+ let(:parent) { EmmParent.new }
2234
+
2235
+ before do
2236
+ parent.blocks << EmmBlock.new(_id: nil, name: 'test', children: [size: 1, order: 1])
2237
+ parent.blocks << EmmBlock.new(_id: nil, name: 'test2', children: [size: 1, order: 1])
2238
+ parent.save!
2239
+
2240
+ parent.blocks.destroy_all(:name => 'test')
2241
+ end
2242
+
2243
+ it "deletes only the matching documents in the database" do
2244
+ expect(parent.reload.blocks.length).to eq(1)
2245
+ end
2246
+ end
2247
+
2248
+ # Since without an _id field we must us a $pullAll with the attributes of
2249
+ # the embedded document, if you modify it beforehand, the query will not
2250
+ # be able to find the correct document to pull.
2251
+ context "when modifying the document with nil _id" do
2252
+ let(:parent) { EmmParent.new }
2253
+
2254
+ before do
2255
+ parent.blocks << EmmBlock.new(_id: nil, name: 'test', children: [size: 1, order: 1])
2256
+ parent.blocks << EmmBlock.new(_id: nil, name: 'test2', children: [size: 1, order: 1])
2257
+ parent.save!
2258
+
2259
+ parent.blocks[0].children[0].assign_attributes(size: 2)
2260
+
2261
+ parent.blocks.destroy_all(:name => 'test')
2262
+ end
2263
+
2264
+ it "does not delete the correct documents" do
2265
+ expect(parent.reload.blocks.length).to eq(2)
2266
+ end
2267
+ end
2268
+
2269
+ context "when documents with and without _id" do
2270
+ let(:parent) { EmmParent.new }
2271
+
2272
+ before do
2273
+ parent.blocks << EmmBlock.new(_id: nil, name: 'test', children: [size: 1, order: 1])
2274
+ parent.blocks << EmmBlock.new(name: 'test', children: [size: 1, order: 1])
2275
+ parent.save!
2276
+
2277
+ parent.blocks[1].children[0].assign_attributes(size: 2)
2278
+
2279
+ parent.blocks.destroy_all(:name => 'test')
2280
+ end
2281
+
2282
+ it "does not delete the correct documents" do
2283
+ expect(parent.reload.blocks.length).to eq(0)
2284
+ end
2285
+ end
2213
2286
  end
2214
2287
  end
2215
2288
 
@@ -2287,7 +2360,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
2287
2360
  it "raises an error" do
2288
2361
  expect {
2289
2362
  person.addresses.find(BSON::ObjectId.new)
2290
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
2363
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Address with id\(s\)/)
2291
2364
  end
2292
2365
  end
2293
2366
 
@@ -2336,7 +2409,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
2336
2409
  it "raises an error" do
2337
2410
  expect {
2338
2411
  person.addresses.find([ BSON::ObjectId.new ])
2339
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
2412
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Address with id\(s\)/)
2340
2413
  end
2341
2414
  end
2342
2415
 
@@ -3461,7 +3534,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3461
3534
 
3462
3535
  describe "replacing the entire embedded list" do
3463
3536
 
3464
- context "when an embeds many relationship contains a nil as the first item" do
3537
+ context "when an embeds many relationship contains nil as the first item" do
3465
3538
 
3466
3539
  let(:person) do
3467
3540
  Person.create!
@@ -3482,7 +3555,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3482
3555
  end
3483
3556
  end
3484
3557
 
3485
- context "when an embeds many relationship contains a nil in the middle of the list" do
3558
+ context "when an embeds many relationship contains nil in the middle of the list" do
3486
3559
 
3487
3560
  let(:person) do
3488
3561
  Person.create!
@@ -3503,7 +3576,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3503
3576
  end
3504
3577
  end
3505
3578
 
3506
- context "when an embeds many relationship contains a nil at the end of the list" do
3579
+ context "when an embeds many relationship contains nil at the end of the list" do
3507
3580
 
3508
3581
  let(:person) do
3509
3582
  Person.create!
@@ -3527,7 +3600,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3527
3600
 
3528
3601
  describe "appending to the embedded list" do
3529
3602
 
3530
- context "when appending a nil to the first position in an embedded list" do
3603
+ context "when appending nil to the first position in an embedded list" do
3531
3604
 
3532
3605
  let(:person) do
3533
3606
  Person.create! phone_numbers: []
@@ -3546,7 +3619,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3546
3619
  end
3547
3620
  end
3548
3621
 
3549
- context "when appending a nil into the middle of an embedded list" do
3622
+ context "when appending nil into the middle of an embedded list" do
3550
3623
 
3551
3624
  let(:person) do
3552
3625
  Person.create! phone_numbers: []
@@ -3565,7 +3638,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3565
3638
  end
3566
3639
  end
3567
3640
 
3568
- context "when appending a nil to the end of an embedded list" do
3641
+ context "when appending nil to the end of an embedded list" do
3569
3642
 
3570
3643
  let(:person) do
3571
3644
  Person.create! phone_numbers: []
@@ -3960,6 +4033,28 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3960
4033
  end
3961
4034
  end
3962
4035
 
4036
+ context "when destroying a document with multiple nil _ids" do
4037
+ let(:congress) { EmmCongress.create! }
4038
+
4039
+ before do
4040
+ congress.legislators << EmmLegislator.new(_id: nil, a: 1)
4041
+ congress.legislators << EmmLegislator.new(_id: nil, a: 2)
4042
+
4043
+ congress.legislators[0].destroy
4044
+ end
4045
+
4046
+ it "deletes the correct document locally" do
4047
+ pending "MONGOID-5394"
4048
+ expect(congress.legislators.length).to eq(1)
4049
+ expect(congress.legislators.first.a).to eq(1)
4050
+ end
4051
+
4052
+ it "only deletes the one document" do
4053
+ pending "MONGOID-5394"
4054
+ expect(congress.reload.legislators.length).to eq(1)
4055
+ end
4056
+ end
4057
+
3963
4058
  context "when adding a document" do
3964
4059
 
3965
4060
  let(:person) do
@@ -4651,6 +4746,55 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
4651
4746
  end
4652
4747
  end
4653
4748
 
4749
+ context "when trying to persist the empty list" do
4750
+
4751
+ context "in an embeds_many relation" do
4752
+
4753
+ let(:band) { Band.create! }
4754
+
4755
+ before do
4756
+ band.labels = []
4757
+ band.save!
4758
+ end
4759
+
4760
+ let(:reloaded_band) { Band.collection.find(_id: band._id).first }
4761
+
4762
+ it "persists the empty list" do
4763
+ expect(reloaded_band).to have_key(:labels)
4764
+ expect(reloaded_band[:labels]).to eq []
4765
+ end
4766
+ end
4767
+
4768
+ context "in a nested embeds_many relation" do
4769
+
4770
+ let(:survey) { Survey.create!(questions: [Question.new]) }
4771
+
4772
+ before do
4773
+ survey.questions.first.answers = []
4774
+ survey.save!
4775
+ end
4776
+
4777
+ let(:reloaded_survey) { Survey.collection.find(_id: survey._id).first }
4778
+
4779
+ it "persists the empty list" do
4780
+ expect(reloaded_survey).to have_key(:questions)
4781
+ expect(reloaded_survey[:questions][0]).to have_key(:answers)
4782
+ expect(reloaded_survey[:questions][0][:answers]).to eq []
4783
+ end
4784
+ end
4785
+
4786
+ context "when not setting the embeds_many field" do
4787
+
4788
+ let(:band) { Band.create! }
4789
+
4790
+ let(:reloaded_band) { Band.collection.find(_id: band._id).first }
4791
+
4792
+ it "does not persist the empty list" do
4793
+ expect(reloaded_band).to_not have_key(:labels)
4794
+ end
4795
+ end
4796
+ end
4797
+
4654
4798
  context "when using assign_attributes with an already populated array" do
4655
4799
  let(:post) { EmmPost.create! }
4656
4800
 
@@ -4670,4 +4814,50 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
4670
4814
  expect(post.company_tags.first.title).to eq("c")
4671
4815
  end
4672
4816
  end
4817
+
4818
+ context "when the parent fails validation" do
4819
+ let(:school) { EmmSchool.new }
4820
+ let(:student) { school.students.new }
4821
+
4822
+ before do
4823
+ student.save
4824
+ end
4825
+
4826
+ it "does not mark the parent as persisted" do
4827
+ expect(school.persisted?).to be false
4828
+ end
4829
+
4830
+ it "does not mark the child as persisted" do
4831
+ expect(student.persisted?).to be false
4832
+ end
4833
+
4834
+ it "does not persist the parent" do
4835
+ expect(School.count).to eq(0)
4836
+ end
4837
+ end
4838
+
4839
+ context "when doing assign_attributes then assignment" do
4840
+
4841
+ let(:post) do
4842
+ EmmPost.create!(
4843
+ company_tags: [ EmmCompanyTag.new(title: "1"), EmmCompanyTag.new(title: "1") ],
4844
+ user_tags: [ EmmUserTag.new(title: "1"), EmmUserTag.new(title: "1") ]
4845
+ )
4846
+ end
4847
+
4848
+ let(:from_db) { EmmPost.find(post.id) }
4849
+
4850
+ before do
4851
+ post.assign_attributes(
4852
+ company_tags: [ EmmCompanyTag.new(title: '3'), EmmCompanyTag.new(title: '4') ]
4853
+ )
4854
+ post.user_tags = [ EmmUserTag.new(title: '3'), EmmUserTag.new(title: '4') ]
4855
+ post.save!
4856
+ end
4857
+
4858
+ it "persists the associations correctly" do
4859
+ expect(from_db.user_tags.size).to eq(2)
4860
+ expect(from_db.company_tags.size).to eq(2)
4861
+ end
4862
+ end
4673
4863
  end
@@ -188,3 +188,39 @@ class EmmUserTag
188
188
  embedded_in :post, class_name: "EmmPost"
189
189
  end
190
190
 
191
+ class EmmSchool
192
+ include Mongoid::Document
193
+
194
+ embeds_many :students, class_name: "EmmStudent"
195
+
196
+ field :name, type: :string
197
+
198
+ validates :name, presence: true
199
+ end
200
+
201
+ class EmmStudent
202
+ include Mongoid::Document
203
+
204
+ embedded_in :school, class_name: "EmmSchool"
205
+ end
206
+
207
+ class EmmParent
208
+ include Mongoid::Document
209
+ embeds_many :blocks, class_name: "EmmBlock"
210
+ end
211
+
212
+ class EmmBlock
213
+ include Mongoid::Document
214
+ field :name, type: String
215
+ embeds_many :children, class_name: "EmmChild"
216
+ end
217
+
218
+ class EmmChild
219
+ include Mongoid::Document
220
+ embedded_in :block, class_name: "EmmBlock"
221
+
222
+ field :size, type: Integer
223
+ field :order, type: Integer
224
+ field :t
225
+ end
226
+
@@ -47,5 +47,17 @@ describe Mongoid::Association::Embedded::EmbedsMany do
47
47
  expect(patient.addresses.first.number).to eq(123)
48
48
  end
49
49
  end
50
+
51
+ context "when excluding the relation" do
52
+ let(:congress) do
53
+ EmmCongress.where(name: 'foo').only(:_id).first
54
+ end
55
+
56
+ it 'raises a MissingAttributeError' do
57
+ expect do
58
+ congress.legislators
59
+ end.to raise_error(ActiveModel::MissingAttributeError)
60
+ end
61
+ end
50
62
  end
51
63
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "spec_helper"
4
+ require_relative 'embeds_many_models'
4
5
 
5
6
  describe Mongoid::Association::Embedded::EmbedsMany do
6
7
 
@@ -861,4 +862,71 @@ describe Mongoid::Association::Embedded::EmbedsMany do
861
862
  expect(association.path(double( :_parent => true))).to be_a(Mongoid::Atomic::Paths::Embedded::Many)
862
863
  end
863
864
  end
865
+
866
+ context "when the document and embedded document's klass is in a submodule" do
867
+
868
+ let(:tank) { EmmSpec::Tank.create! }
869
+ let(:gun) { tank.guns.create! }
870
+
871
+ let(:inverse_assoc) { gun._association.inverse_association }
872
+
873
+ it "has the correct inverses" do
874
+ pending 'MONGOID-5080'
875
+
876
+ inverse_assoc.should be_a(Mongoid::Association::Embedded::EmbeddedIn)
877
+ inverse_assoc.name.should == :tank
878
+ end
879
+
880
+ context "when embedded association is not namespaced but has class_name" do
881
+
882
+ let(:turret) { tank.emm_turrets.create! }
883
+
884
+ let(:inverse_assoc) { turret._association.inverse_association }
885
+
886
+ it "has the correct inverses" do
887
+ inverse_assoc.should be_a(Mongoid::Association::Embedded::EmbeddedIn)
888
+ inverse_assoc.name.should == :tank
889
+ end
890
+ end
891
+
892
+ context "when embedded association is not namespaced and lacks class_name" do
893
+
894
+ let(:hatch) { tank.emm_hatches.create! }
895
+
896
+ let(:inverse_assoc) { hatch._association.inverse_association }
897
+
898
+ it "does not find the inverse" do
899
+ inverse_assoc.should be nil
900
+ end
901
+ end
902
+
903
+ context "when the class names exist on top level and namespaced" do
904
+
905
+ let(:car) { EmmSpec::Car.create! }
906
+ let(:door) { car.doors.create! }
907
+
908
+ let(:inverse_assoc) { door._association.inverse_association }
909
+
910
+ it "has the correct inverses" do
911
+ pending 'MONGOID-5080'
912
+
913
+ inverse_assoc.should be_a(Mongoid::Association::Embedded::EmbeddedIn)
914
+ inverse_assoc.name.should == :car
915
+ end
916
+ end
917
+
918
+ context "when the association has an unqualified class_name in same module" do
919
+
920
+ let(:launcher) { tank.launchers.create! }
921
+
922
+ let(:inverse_assoc) { launcher._association.inverse_association }
923
+
924
+ it "has the correct inverses" do
925
+ pending 'unqualified class_name arguments do not work per MONGOID-5080'
926
+
927
+ inverse_assoc.should be_a(Mongoid::Association::Embedded::EmbeddedIn)
928
+ inverse_assoc.name.should == :tank
929
+ end
930
+ end
931
+ end
864
932
  end
@@ -78,4 +78,29 @@ describe Mongoid::Association::Embedded::EmbedsOne::Buildable do
78
78
  end
79
79
  end
80
80
  end
81
+
82
+ context 'when the object is already associated with another object' do
83
+
84
+ let(:owner1) do
85
+ Owner.create!
86
+ end
87
+
88
+ let(:owner2) do
89
+ Owner.create!
90
+ end
91
+
92
+ let(:scribe) do
93
+ Scribe.new
94
+ end
95
+
96
+ before do
97
+ owner1.scribe = scribe
98
+ owner2.scribe = scribe
99
+ end
100
+
101
+ it 'clears the object of its previous association' do
102
+ expect(owner1.scribe).to be_nil
103
+ expect(owner2.scribe).to eq(scribe)
104
+ end
105
+ end
81
106
  end
@@ -52,3 +52,22 @@ class EomDnlChild
52
52
  embedded_in :parent, class_name: 'EomDnlParent'
53
53
  embedded_in :missing_parent, class_name: 'EomDnlMissingParent'
54
54
  end
55
+
56
+ class EomAddress
57
+ include Mongoid::Document
58
+
59
+ field :city, type: String
60
+
61
+ embedded_in :addressable, polymorphic: true
62
+ end
63
+
64
+ # app/models/company.rb
65
+ class EomCompany
66
+ include Mongoid::Document
67
+
68
+ embeds_one :address, class_name: 'EomAddress', as: :addressable
69
+ accepts_nested_attributes_for :address
70
+
71
+ embeds_one :delivery_address, class_name: 'EomAddress', as: :addressable
72
+ accepts_nested_attributes_for :delivery_address
73
+ end
@@ -953,4 +953,32 @@ describe Mongoid::Association::Embedded::EmbedsOne do
953
953
  expect(association.create_relation(owner, target)).to be_a(EmbeddedObject)
954
954
  end
955
955
  end
956
+
957
+ context "when multiple embeds_one associations reference the same class" do
958
+ let(:acme) { EomCompany.create(address: { city: 'Gotham' }, delivery_address: { city: 'Parcelville' }) }
959
+
960
+ context "when the first assignment is modified" do
961
+ before do
962
+ acme.update(address: EomAddress.new(city: 'Bigville'))
963
+ acme.reload
964
+ end
965
+
966
+ it "updates the correct association" do
967
+ expect(acme.address.city).to eq("Bigville")
968
+ expect(acme.delivery_address.city).to eq("Parcelville")
969
+ end
970
+ end
971
+
972
+ context "when the second assignment is modified" do
973
+ before do
974
+ acme.update(delivery_address: EomAddress.new(city: 'Bigville'))
975
+ acme.reload
976
+ end
977
+
978
+ it "updates the correct association" do
979
+ expect(acme.address.city).to eq("Gotham")
980
+ expect(acme.delivery_address.city).to eq("Bigville")
981
+ end
982
+ end
983
+ end
956
984
  end
@@ -83,7 +83,8 @@ describe Mongoid::Association::Referenced::BelongsTo::Binding do
83
83
  end
84
84
 
85
85
  it "does nothing" do
86
- expect(game).to receive(:person=).never
86
+ expect(game).to receive(:person=).with(person).never
87
+ expect(game).to receive(:person=).with(nil).once
87
88
  binding.bind_one
88
89
  end
89
90
  end
@@ -235,4 +235,58 @@ describe Mongoid::Association::Referenced::BelongsTo::Buildable do
235
235
  end
236
236
  end
237
237
  end
238
+
239
+ context 'when the object is already associated with another object' do
240
+
241
+ context "when inverse is has_many" do
242
+
243
+ let(:drug1) do
244
+ Drug.create!
245
+ end
246
+
247
+ let(:drug2) do
248
+ Drug.create!
249
+ end
250
+
251
+ let(:person) do
252
+ Person.create!
253
+ end
254
+
255
+ before do
256
+ drug1.person = person
257
+ drug2.person = person
258
+ end
259
+
260
+ it 'does not clear the object of its previous association' do
261
+ expect(drug1.person).to eq(person)
262
+ expect(drug2.person).to eq(person)
263
+ expect(person.drugs).to eq([drug1, drug2])
264
+ end
265
+ end
266
+
267
+ context "when inverse is has_one" do
268
+
269
+ let(:account1) do
270
+ Account.create!(name: "1")
271
+ end
272
+
273
+ let(:account2) do
274
+ Account.create!(name: "2")
275
+ end
276
+
277
+ let(:person) do
278
+ Person.create!
279
+ end
280
+
281
+ before do
282
+ account1.person = person
283
+ account2.person = person
284
+ end
285
+
286
+ it 'clears the object of its previous association' do
287
+ expect(account1.person).to be_nil
288
+ expect(account2.person).to eq(person)
289
+ end
290
+ end
291
+ end
238
292
  end