mongoid 7.5.0 → 8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (286) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +3 -3
  4. data/lib/config/locales/en.yml +46 -30
  5. data/lib/mongoid/association/accessors.rb +32 -3
  6. data/lib/mongoid/association/bindable.rb +48 -0
  7. data/lib/mongoid/association/builders.rb +4 -2
  8. data/lib/mongoid/association/eager_loadable.rb +29 -7
  9. data/lib/mongoid/association/embedded/batchable.rb +48 -8
  10. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  11. data/lib/mongoid/association/embedded/embedded_in.rb +2 -1
  12. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  13. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +1 -1
  14. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +40 -18
  15. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +18 -4
  16. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +21 -2
  17. data/lib/mongoid/association/macros.rb +2 -1
  18. data/lib/mongoid/association/many.rb +5 -0
  19. data/lib/mongoid/association/nested/many.rb +2 -1
  20. data/lib/mongoid/association/proxy.rb +12 -0
  21. data/lib/mongoid/association/referenced/auto_save.rb +3 -2
  22. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  23. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  24. data/lib/mongoid/association/referenced/belongs_to.rb +1 -1
  25. data/lib/mongoid/association/referenced/counter_cache.rb +8 -8
  26. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +64 -11
  27. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +4 -1
  28. data/lib/mongoid/association/referenced/has_many/enumerable.rb +10 -18
  29. data/lib/mongoid/association/referenced/has_many/proxy.rb +12 -9
  30. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  31. data/lib/mongoid/association/referenced/has_one/proxy.rb +8 -11
  32. data/lib/mongoid/association/referenced/syncable.rb +2 -2
  33. data/lib/mongoid/association/relatable.rb +38 -4
  34. data/lib/mongoid/atomic/paths/embedded/many.rb +19 -0
  35. data/lib/mongoid/attributes/processing.rb +9 -2
  36. data/lib/mongoid/attributes.rb +30 -27
  37. data/lib/mongoid/changeable.rb +37 -2
  38. data/lib/mongoid/clients/options.rb +4 -0
  39. data/lib/mongoid/clients/sessions.rb +2 -14
  40. data/lib/mongoid/config.rb +20 -10
  41. data/lib/mongoid/contextual/aggregable/memory.rb +23 -15
  42. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  43. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  44. data/lib/mongoid/contextual/memory.rb +55 -28
  45. data/lib/mongoid/contextual/mongo.rb +173 -245
  46. data/lib/mongoid/contextual/none.rb +33 -15
  47. data/lib/mongoid/copyable.rb +32 -8
  48. data/lib/mongoid/criteria/includable.rb +24 -20
  49. data/lib/mongoid/criteria/marshalable.rb +10 -2
  50. data/lib/mongoid/criteria/queryable/extensions/array.rb +2 -15
  51. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  52. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  53. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  54. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  55. data/lib/mongoid/criteria/queryable/extensions/hash.rb +0 -16
  56. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  57. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  58. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  59. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +1 -1
  60. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +3 -1
  61. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  62. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  63. data/lib/mongoid/criteria/queryable/optional.rb +3 -9
  64. data/lib/mongoid/criteria/queryable/options.rb +1 -1
  65. data/lib/mongoid/criteria/queryable/selectable.rb +2 -24
  66. data/lib/mongoid/criteria/queryable/selector.rb +89 -4
  67. data/lib/mongoid/criteria/queryable/smash.rb +39 -6
  68. data/lib/mongoid/criteria/queryable.rb +11 -6
  69. data/lib/mongoid/criteria.rb +1 -28
  70. data/lib/mongoid/deprecable.rb +36 -0
  71. data/lib/mongoid/deprecation.rb +25 -0
  72. data/lib/mongoid/document.rb +96 -34
  73. data/lib/mongoid/errors/document_not_found.rb +6 -2
  74. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  75. data/lib/mongoid/errors/invalid_field.rb +5 -1
  76. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  77. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  78. data/lib/mongoid/errors.rb +2 -2
  79. data/lib/mongoid/extensions/array.rb +8 -6
  80. data/lib/mongoid/extensions/big_decimal.rb +29 -10
  81. data/lib/mongoid/extensions/binary.rb +42 -0
  82. data/lib/mongoid/extensions/boolean.rb +8 -2
  83. data/lib/mongoid/extensions/date.rb +26 -20
  84. data/lib/mongoid/extensions/date_time.rb +1 -1
  85. data/lib/mongoid/extensions/float.rb +4 -5
  86. data/lib/mongoid/extensions/hash.rb +12 -5
  87. data/lib/mongoid/extensions/integer.rb +4 -5
  88. data/lib/mongoid/extensions/object.rb +2 -0
  89. data/lib/mongoid/extensions/range.rb +41 -10
  90. data/lib/mongoid/extensions/regexp.rb +11 -4
  91. data/lib/mongoid/extensions/set.rb +11 -4
  92. data/lib/mongoid/extensions/string.rb +2 -13
  93. data/lib/mongoid/extensions/symbol.rb +3 -14
  94. data/lib/mongoid/extensions/time.rb +27 -16
  95. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  96. data/lib/mongoid/extensions.rb +1 -0
  97. data/lib/mongoid/factory.rb +42 -7
  98. data/lib/mongoid/fields/foreign_key.rb +7 -0
  99. data/lib/mongoid/fields/validators/macro.rb +3 -9
  100. data/lib/mongoid/fields.rb +49 -7
  101. data/lib/mongoid/findable.rb +21 -16
  102. data/lib/mongoid/indexable/specification.rb +1 -1
  103. data/lib/mongoid/indexable/validators/options.rb +4 -1
  104. data/lib/mongoid/interceptable.rb +69 -9
  105. data/lib/mongoid/persistable/creatable.rb +14 -5
  106. data/lib/mongoid/persistable/updatable.rb +12 -5
  107. data/lib/mongoid/persistence_context.rb +19 -2
  108. data/lib/mongoid/query_cache.rb +6 -258
  109. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  110. data/lib/mongoid/reloadable.rb +7 -3
  111. data/lib/mongoid/selectable.rb +1 -2
  112. data/lib/mongoid/stateful.rb +27 -1
  113. data/lib/mongoid/timestamps/created.rb +1 -1
  114. data/lib/mongoid/timestamps/updated.rb +1 -1
  115. data/lib/mongoid/touchable.rb +2 -3
  116. data/lib/mongoid/traversable.rb +1 -0
  117. data/lib/mongoid/validatable/uniqueness.rb +2 -1
  118. data/lib/mongoid/version.rb +1 -1
  119. data/lib/mongoid/warnings.rb +3 -4
  120. data/lib/mongoid.rb +1 -0
  121. data/spec/config/mongoid.yml +16 -0
  122. data/spec/integration/app_spec.rb +8 -12
  123. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  124. data/spec/integration/associations/embedded_spec.rb +15 -0
  125. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  126. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  127. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  128. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  129. data/spec/integration/associations/has_one_spec.rb +97 -1
  130. data/spec/integration/associations/scope_option_spec.rb +1 -1
  131. data/spec/integration/callbacks_models.rb +95 -1
  132. data/spec/integration/callbacks_spec.rb +226 -4
  133. data/spec/integration/criteria/range_spec.rb +95 -1
  134. data/spec/integration/discriminator_key_spec.rb +115 -76
  135. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  136. data/spec/integration/i18n_fallbacks_spec.rb +1 -15
  137. data/spec/integration/matcher_examples_spec.rb +20 -13
  138. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  139. data/spec/integration/matcher_operator_spec.rb +3 -5
  140. data/spec/integration/persistence/range_field_spec.rb +350 -0
  141. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  142. data/spec/mongoid/association/depending_spec.rb +9 -9
  143. data/spec/mongoid/association/eager_spec.rb +2 -1
  144. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  145. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  146. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +69 -9
  147. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  148. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +219 -8
  149. data/spec/mongoid/association/embedded/embeds_many_models.rb +157 -0
  150. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
  151. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  152. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  153. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  154. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  155. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  156. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  157. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  158. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  159. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -2
  160. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +67 -4
  161. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  162. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  163. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  164. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2 -56
  165. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +82 -13
  166. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  167. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  168. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  169. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  170. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  171. data/spec/mongoid/association/syncable_spec.rb +14 -0
  172. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  173. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  174. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  175. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  176. data/spec/mongoid/attributes_spec.rb +524 -27
  177. data/spec/mongoid/changeable_spec.rb +130 -13
  178. data/spec/mongoid/clients/factory_spec.rb +23 -30
  179. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  180. data/spec/mongoid/clients_spec.rb +32 -2
  181. data/spec/mongoid/config_spec.rb +58 -13
  182. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  183. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  184. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  185. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  186. data/spec/mongoid/contextual/memory_spec.rb +521 -14
  187. data/spec/mongoid/contextual/mongo_spec.rb +564 -394
  188. data/spec/mongoid/contextual/none_spec.rb +11 -19
  189. data/spec/mongoid/copyable_spec.rb +451 -1
  190. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  191. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  192. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  193. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  194. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  195. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  196. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  197. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  198. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  199. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  200. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  201. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  202. data/spec/mongoid/criteria/queryable/optional_spec.rb +0 -484
  203. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  204. data/spec/mongoid/criteria/queryable/selectable_spec.rb +77 -85
  205. data/spec/mongoid/criteria/queryable/selector_spec.rb +14 -2
  206. data/spec/mongoid/criteria_spec.rb +469 -1201
  207. data/spec/mongoid/document_fields_spec.rb +173 -24
  208. data/spec/mongoid/document_spec.rb +32 -41
  209. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  210. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  211. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  212. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  213. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  214. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  215. data/spec/mongoid/extensions/array_spec.rb +16 -2
  216. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  217. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  218. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  219. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  220. data/spec/mongoid/extensions/date_spec.rb +71 -1
  221. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  222. data/spec/mongoid/extensions/float_spec.rb +48 -76
  223. data/spec/mongoid/extensions/hash_spec.rb +30 -0
  224. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  225. data/spec/mongoid/extensions/range_spec.rb +255 -54
  226. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  227. data/spec/mongoid/extensions/set_spec.rb +106 -0
  228. data/spec/mongoid/extensions/string_spec.rb +53 -25
  229. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  230. data/spec/mongoid/extensions/time_spec.rb +634 -66
  231. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  232. data/spec/mongoid/factory_spec.rb +61 -1
  233. data/spec/mongoid/fields_spec.rb +321 -50
  234. data/spec/mongoid/findable_spec.rb +64 -29
  235. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  236. data/spec/mongoid/indexable_spec.rb +16 -19
  237. data/spec/mongoid/interceptable_spec.rb +584 -5
  238. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  239. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  240. data/spec/mongoid/mongoizable_spec.rb +285 -0
  241. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  242. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  243. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  244. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  245. data/spec/mongoid/persistence_context_spec.rb +50 -1
  246. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  247. data/spec/mongoid/query_cache_spec.rb +0 -154
  248. data/spec/mongoid/reloadable_spec.rb +35 -2
  249. data/spec/mongoid/scopable_spec.rb +21 -1
  250. data/spec/mongoid/shardable_spec.rb +14 -0
  251. data/spec/mongoid/stateful_spec.rb +28 -0
  252. data/spec/mongoid/timestamps_spec.rb +390 -0
  253. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  254. data/spec/mongoid/touchable_spec.rb +116 -0
  255. data/spec/mongoid/touchable_spec_models.rb +12 -8
  256. data/spec/mongoid/traversable_spec.rb +4 -11
  257. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  258. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  259. data/spec/mongoid/warnings_spec.rb +35 -0
  260. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  261. data/spec/rails/mongoid_spec.rb +4 -16
  262. data/spec/shared/lib/mrss/event_subscriber.rb +5 -15
  263. data/spec/support/constraints.rb +24 -0
  264. data/spec/support/macros.rb +30 -0
  265. data/spec/support/models/augmentation.rb +12 -0
  266. data/spec/support/models/band.rb +3 -0
  267. data/spec/support/models/catalog.rb +24 -0
  268. data/spec/support/models/circus.rb +3 -0
  269. data/spec/support/models/fanatic.rb +8 -0
  270. data/spec/support/models/implant.rb +9 -0
  271. data/spec/support/models/label.rb +2 -0
  272. data/spec/support/models/passport.rb +9 -0
  273. data/spec/support/models/person.rb +1 -0
  274. data/spec/support/models/player.rb +2 -0
  275. data/spec/support/models/powerup.rb +12 -0
  276. data/spec/support/models/registry.rb +1 -0
  277. data/spec/support/models/school.rb +14 -0
  278. data/spec/support/models/shield.rb +18 -0
  279. data/spec/support/models/student.rb +14 -0
  280. data/spec/support/models/weapon.rb +12 -0
  281. data.tar.gz.sig +0 -0
  282. metadata +48 -12
  283. metadata.gz.sig +0 -0
  284. data/lib/mongoid/errors/eager_load.rb +0 -23
  285. data/lib/mongoid/errors/invalid_value.rb +0 -17
  286. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
@@ -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
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "spec_helper"
4
+ require_relative '../belongs_to_models.rb'
4
5
 
5
6
  describe Mongoid::Association::Referenced::BelongsTo::Proxy do
6
7
 
@@ -1368,6 +1369,20 @@ describe Mongoid::Association::Referenced::BelongsTo::Proxy do
1368
1369
  game.person.set_personal_data(ssn: '123', age: 25)
1369
1370
  end.not_to raise_error
1370
1371
  end
1372
+ end
1373
+
1374
+ # This is a very specific case, see MONGOID-5089 for more details.
1375
+ context "when required is false, child is an orphan, and parent has explicit _id" do
1376
+ let(:comment) { BTMComment.create! }
1377
+ let(:article) do
1378
+ BTMArticle.new(
1379
+ comment_ids: [comment.id],
1380
+ id: 1
1381
+ )
1382
+ end
1371
1383
 
1384
+ it "uses the correct explicit id" do
1385
+ expect(article.comments.first.article_id).to eq(1)
1386
+ end
1372
1387
  end
1373
1388
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BTMArticle
4
+ include Mongoid::Document
5
+ has_many :comments, class_name: "BTMComment"
6
+ end
7
+
8
+ class BTMComment
9
+ include Mongoid::Document
10
+ belongs_to :article, class_name: "BTMArticle", required: false
11
+ end
@@ -2019,8 +2019,8 @@ describe Mongoid::Association::Referenced::BelongsTo do
2019
2019
 
2020
2020
  describe '#foreign_key_check' do
2021
2021
 
2022
- it 'returns the foreign_key followed by "_changed?"' do
2023
- expect(association.foreign_key_check).to eq('owner_object_id_changed?')
2022
+ it 'returns the foreign_key followed by "_previously_changed?"' do
2023
+ expect(association.foreign_key_check).to eq('owner_object_id_previously_changed?')
2024
2024
  end
2025
2025
  end
2026
2026
 
@@ -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"
4
5
 
5
6
  describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
6
7
 
@@ -2394,6 +2395,10 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
2394
2395
  it "removes the ids from the foreign key" do
2395
2396
  expect(person.preference_ids).to eq([ preference_two.id ])
2396
2397
  end
2398
+
2399
+ it "sets the association locally" do
2400
+ expect(person.preferences).to eq([preference_two])
2401
+ end
2397
2402
  end
2398
2403
 
2399
2404
  context "when conditions are not provided" do
@@ -2420,6 +2425,10 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
2420
2425
  it "returns the number of documents deleted" do
2421
2426
  expect(deleted).to eq(2)
2422
2427
  end
2428
+
2429
+ it "sets the association locally" do
2430
+ expect(person.preferences).to eq([])
2431
+ end
2423
2432
  end
2424
2433
  end
2425
2434
  end
@@ -2507,7 +2516,7 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
2507
2516
  it "raises an error" do
2508
2517
  expect {
2509
2518
  preference
2510
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
2519
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Preference with id\(s\)/)
2511
2520
  end
2512
2521
  end
2513
2522
 
@@ -2522,7 +2531,7 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
2522
2531
  it "raises an error" do
2523
2532
  expect {
2524
2533
  person.preferences.find(BSON::ObjectId.new)
2525
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
2534
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Preference with id\(s\)/)
2526
2535
  end
2527
2536
  end
2528
2537
 
@@ -2571,7 +2580,7 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
2571
2580
  it "raises an error" do
2572
2581
  expect {
2573
2582
  preferences
2574
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
2583
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Preference with id\(s\)/)
2575
2584
  end
2576
2585
  end
2577
2586
 
@@ -2586,7 +2595,7 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
2586
2595
  it "raises an error" do
2587
2596
  expect {
2588
2597
  person.preferences.find([ BSON::ObjectId.new ])
2589
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
2598
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Preference with id\(s\)/)
2590
2599
  end
2591
2600
  end
2592
2601
 
@@ -3770,4 +3779,58 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
3770
3779
  expect(p2.d_ids).to match_array([d2.id])
3771
3780
  end
3772
3781
  end
3782
+
3783
+ context "when accesing own _id from parent's foreign key in default" do
3784
+ let!(:contract) { HabtmmContract.create! }
3785
+ let!(:signature) { contract.signatures.create! }
3786
+
3787
+ it "is nil" do
3788
+ expect(signature.favorite_signature).to be nil
3789
+ end
3790
+ end
3791
+
3792
+ context "when setting an association on a model that uses the class_name option" do
3793
+ let!(:contract) { HabtmmContract.create! }
3794
+ let!(:signature) { HabtmmSignature.create!(contracts: [contract]) }
3795
+
3796
+ it "populates the inverse foreign key" do
3797
+ expect(signature.contracts.first.signature_ids).to eq([signature.id])
3798
+ end
3799
+ end
3800
+
3801
+ context "when there is a foreign key in the aliased associations" do
3802
+ it "has the correct aliases" do
3803
+ expect(Dog.aliased_associations["breed_ids"]).to eq("breeds")
3804
+ expect(Breed.aliased_associations["dog_ids"]).to eq("dogs")
3805
+ end
3806
+ end
3807
+
3808
+ # This test is for MONGOID-5344 which tests that the initial call to
3809
+ # signature_ids refers to the same array as subsequent calls to signature_ids.
3810
+ # Prior to the change in that ticket, this test broke because the array
3811
+ # returned from write_attribute (which is triggered the first time the
3812
+ # foreign key array is referenced, to set the default), refers to a different
3813
+ # array to the one stored in the attributes hash. This happened because,
3814
+ # when retrieving a document from the database, the attributes hash is actually
3815
+ # a BSON::Document, which applies a transformation to the array before
3816
+ # storing it.
3817
+ context "when executing concat on foreign key array from the db" do
3818
+ config_override :legacy_attributes, false
3819
+
3820
+ before do
3821
+ HabtmmContract.create!
3822
+ HabtmmSignature.create!
3823
+ end
3824
+
3825
+ let!(:contract) { HabtmmContract.first }
3826
+ let!(:signature) { HabtmmSignature.first }
3827
+
3828
+ before do
3829
+ contract.signature_ids.concat([signature.id])
3830
+ end
3831
+
3832
+ it "works on the first attempt" do
3833
+ expect(contract.signature_ids).to eq([signature.id])
3834
+ end
3835
+ end
3773
3836
  end
@@ -32,6 +32,8 @@ end
32
32
  class HabtmmSignature
33
33
  include Mongoid::Document
34
34
 
35
+ field :favorite_signature, default: ->{ contracts.first.signature_ids.first if contracts.first }
36
+
35
37
  has_and_belongs_to_many :contracts, class_name: 'HabtmmContract'
36
38
 
37
39
  field :name, type: String
@@ -65,3 +67,26 @@ class HabtmmAnimal
65
67
 
66
68
  has_and_belongs_to_many :trainers, inverse_of: :animals, class_name: 'HabtmmTrainer', scope: -> { where(name: 'Dave') }
67
69
  end
70
+
71
+ class HabtmmSchool
72
+ include Mongoid::Document
73
+ include Mongoid::Timestamps
74
+
75
+ has_and_belongs_to_many :students, class_name: 'HabtmmStudent'
76
+
77
+ field :after_destroy_triggered, default: false
78
+
79
+ accepts_nested_attributes_for :students, allow_destroy: true
80
+ end
81
+
82
+ class HabtmmStudent
83
+ include Mongoid::Document
84
+ include Mongoid::Timestamps
85
+
86
+ has_and_belongs_to_many :schools, class_name: 'HabtmmSchool'
87
+
88
+ after_destroy do |doc|
89
+ schools.first.update_attributes!(after_destroy_triggered: true) unless schools.empty?
90
+ end
91
+ end
92
+
@@ -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"
4
5
 
5
6
  describe Mongoid::Association::Referenced::HasAndBelongsToMany do
6
7
 
@@ -1008,8 +1009,8 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany do
1008
1009
 
1009
1010
  describe '#foreign_key_check' do
1010
1011
 
1011
- it 'returns the foreign_key followed by "_changed?"' do
1012
- expect(association.foreign_key_check).to eq('has_many_right_object_ids_changed?')
1012
+ it 'returns the foreign_key followed by "_previously_changed?"' do
1013
+ expect(association.foreign_key_check).to eq('has_many_right_object_ids_previously_changed?')
1013
1014
  end
1014
1015
  end
1015
1016
 
@@ -1060,6 +1061,13 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany do
1060
1061
  expect(association.inverse_foreign_key).to eq('bar_ref')
1061
1062
  end
1062
1063
  end
1064
+
1065
+ context "when using a model that uses the class_name option" do
1066
+ let(:inverse_foreign_key) { HabtmmSchool.relations[:students].inverse_foreign_key }
1067
+ it "gets the correct inverse foreign key" do
1068
+ expect(inverse_foreign_key).to eq("school_ids")
1069
+ end
1070
+ end
1063
1071
  end
1064
1072
 
1065
1073
  describe '#inverse_foreign_key_setter' do
@@ -1068,4 +1076,29 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany do
1068
1076
  expect(association.inverse_foreign_key_setter).to eq('has_many_left_object_ids=')
1069
1077
  end
1070
1078
  end
1079
+
1080
+ context "when adding an object to the association" do
1081
+ let!(:start_time) { Timecop.freeze(Time.at(Time.now.to_i)) }
1082
+
1083
+ let(:update_time) do
1084
+ Timecop.freeze(Time.at(Time.now.to_i) + 2)
1085
+ end
1086
+
1087
+ after do
1088
+ Timecop.return
1089
+ end
1090
+
1091
+ let!(:school) { HabtmmSchool.create! }
1092
+ let!(:student) { HabtmmStudent.create! }
1093
+
1094
+ before do
1095
+ update_time
1096
+ school.update(students: [student])
1097
+ end
1098
+
1099
+ it "updates the updated at" do
1100
+ pending "MONGOID-4953"
1101
+ expect(school.updated_at).to eq(update_time)
1102
+ end
1103
+ end
1071
1104
  end
@@ -138,5 +138,114 @@ describe Mongoid::Association::Referenced::HasMany::Buildable do
138
138
  end
139
139
  end
140
140
  end
141
+
142
+ context 'when the object is already associated with another object' do
143
+
144
+ context "when using <<" do
145
+
146
+ let(:person1) do
147
+ Person.new
148
+ end
149
+
150
+ let(:person2) do
151
+ Person.new
152
+ end
153
+
154
+ let(:drug) do
155
+ Drug.new
156
+ end
157
+
158
+ before do
159
+ person1.drugs << drug
160
+ person2.drugs << drug
161
+ end
162
+
163
+ it 'clears the object of its previous association' do
164
+ expect(person1.drugs).to eq([])
165
+ expect(person1.drug_ids).to eq([])
166
+ expect(person2.drugs).to eq([drug])
167
+ expect(person2.drug_ids).to eq([drug._id])
168
+ end
169
+ end
170
+
171
+ context "when using concat" do
172
+
173
+ let(:person1) do
174
+ Person.new
175
+ end
176
+
177
+ let(:person2) do
178
+ Person.new
179
+ end
180
+
181
+ let(:drug) do
182
+ Drug.new
183
+ end
184
+
185
+ before do
186
+ person1.drugs.concat([drug])
187
+ person2.drugs.concat([drug])
188
+ end
189
+
190
+ it 'clears the object of its previous association' do
191
+ expect(person1.drugs).to eq([])
192
+ expect(person1.drug_ids).to eq([])
193
+ expect(person2.drugs).to eq([drug])
194
+ expect(person2.drug_ids).to eq([drug._id])
195
+ end
196
+ end
197
+
198
+ context "when using =" do
199
+
200
+ let(:person1) do
201
+ Person.new
202
+ end
203
+
204
+ let(:person2) do
205
+ Person.new
206
+ end
207
+
208
+ let(:drug) do
209
+ Drug.new
210
+ end
211
+
212
+ before do
213
+ person1.drugs = [drug]
214
+ person2.drugs = [drug]
215
+ end
216
+
217
+ it 'clears the object of its previous association' do
218
+ expect(person1.drugs).to eq([])
219
+ expect(person1.drug_ids).to eq([])
220
+ expect(person2.drugs).to eq([drug])
221
+ expect(person2.drug_ids).to eq([drug._id])
222
+ end
223
+ end
224
+
225
+ context "when using = on the same document twice" do
226
+
227
+ let(:person1) do
228
+ Person.new
229
+ end
230
+
231
+ let(:person2) do
232
+ Person.new
233
+ end
234
+
235
+ let(:drug) do
236
+ Drug.new
237
+ end
238
+
239
+ before do
240
+ person1.drugs = [drug]
241
+ person1.drugs = [drug]
242
+ end
243
+
244
+ it 'clears the object of its previous association' do
245
+ expect(person1.drugs).to eq([drug])
246
+ expect(person1.drug_ids).to eq([drug._id])
247
+ end
248
+ end
249
+ end
141
250
  end
142
251
  end