mongoid 3.1.5 → 8.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1501) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +636 -33
  4. data/LICENSE +2 -1
  5. data/README.md +32 -24
  6. data/Rakefile +75 -5
  7. data/lib/config/locales/en.yml +301 -132
  8. data/lib/mongoid/association/accessors.rb +431 -0
  9. data/lib/mongoid/association/bindable.rb +227 -0
  10. data/lib/mongoid/association/builders.rb +86 -0
  11. data/lib/mongoid/association/constrainable.rb +42 -0
  12. data/lib/mongoid/association/depending.rb +128 -0
  13. data/lib/mongoid/association/eager_loadable.rb +57 -0
  14. data/lib/mongoid/association/embedded/batchable.rb +398 -0
  15. data/lib/mongoid/association/embedded/cyclic.rb +102 -0
  16. data/lib/mongoid/association/embedded/embedded_in/binding.rb +74 -0
  17. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +38 -0
  18. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +111 -0
  19. data/lib/mongoid/association/embedded/embedded_in.rb +135 -0
  20. data/lib/mongoid/association/embedded/embeds_many/binding.rb +42 -0
  21. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +45 -0
  22. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +571 -0
  23. data/lib/mongoid/association/embedded/embeds_many.rb +183 -0
  24. data/lib/mongoid/association/embedded/embeds_one/binding.rb +43 -0
  25. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +53 -0
  26. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +164 -0
  27. data/lib/mongoid/association/embedded/embeds_one.rb +150 -0
  28. data/lib/mongoid/association/embedded.rb +6 -0
  29. data/lib/mongoid/association/macros.rb +228 -0
  30. data/lib/mongoid/association/many.rb +202 -0
  31. data/lib/mongoid/association/marshalable.rb +31 -0
  32. data/lib/mongoid/association/nested/many.rb +192 -0
  33. data/lib/mongoid/association/nested/nested_buildable.rb +66 -0
  34. data/lib/mongoid/association/nested/one.rb +116 -0
  35. data/lib/mongoid/association/nested.rb +15 -0
  36. data/lib/mongoid/association/one.rb +53 -0
  37. data/lib/mongoid/association/options.rb +122 -0
  38. data/lib/mongoid/association/proxy.rb +200 -0
  39. data/lib/mongoid/association/referenced/auto_save.rb +74 -0
  40. data/lib/mongoid/association/referenced/belongs_to/binding.rb +83 -0
  41. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +48 -0
  42. data/lib/mongoid/association/referenced/belongs_to/eager.rb +73 -0
  43. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +124 -0
  44. data/lib/mongoid/association/referenced/belongs_to.rb +226 -0
  45. data/lib/mongoid/association/referenced/counter_cache.rb +152 -0
  46. data/lib/mongoid/association/referenced/eager.rb +163 -0
  47. data/lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb +72 -0
  48. data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +40 -0
  49. data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +53 -0
  50. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +345 -0
  51. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +273 -0
  52. data/lib/mongoid/association/referenced/has_many/binding.rb +36 -0
  53. data/lib/mongoid/association/referenced/has_many/buildable.rb +38 -0
  54. data/lib/mongoid/association/referenced/has_many/eager.rb +44 -0
  55. data/lib/mongoid/association/referenced/has_many/enumerable.rb +494 -0
  56. data/lib/mongoid/association/referenced/has_many/proxy.rb +551 -0
  57. data/lib/mongoid/association/referenced/has_many.rb +251 -0
  58. data/lib/mongoid/association/referenced/has_one/binding.rb +42 -0
  59. data/lib/mongoid/association/referenced/has_one/buildable.rb +74 -0
  60. data/lib/mongoid/association/referenced/has_one/eager.rb +36 -0
  61. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +113 -0
  62. data/lib/mongoid/association/referenced/has_one/proxy.rb +108 -0
  63. data/lib/mongoid/association/referenced/has_one.rb +184 -0
  64. data/lib/mongoid/association/referenced/syncable.rb +155 -0
  65. data/lib/mongoid/association/referenced.rb +9 -0
  66. data/lib/mongoid/association/reflections.rb +69 -0
  67. data/lib/mongoid/association/relatable.rb +489 -0
  68. data/lib/mongoid/association.rb +135 -0
  69. data/lib/mongoid/atomic/modifiers.rb +41 -61
  70. data/lib/mongoid/atomic/paths/embedded/many.rb +24 -8
  71. data/lib/mongoid/atomic/paths/embedded/one.rb +5 -8
  72. data/lib/mongoid/atomic/paths/embedded.rb +3 -34
  73. data/lib/mongoid/atomic/paths/root.rb +4 -20
  74. data/lib/mongoid/atomic/paths.rb +2 -1
  75. data/lib/mongoid/atomic.rb +52 -69
  76. data/lib/mongoid/attributes/dynamic.rb +141 -0
  77. data/lib/mongoid/attributes/nested.rb +93 -0
  78. data/lib/mongoid/attributes/processing.rb +35 -97
  79. data/lib/mongoid/attributes/projector.rb +119 -0
  80. data/lib/mongoid/attributes/readonly.rb +27 -10
  81. data/lib/mongoid/attributes.rb +159 -181
  82. data/lib/mongoid/cacheable.rb +33 -0
  83. data/lib/mongoid/changeable.rb +420 -0
  84. data/lib/mongoid/clients/factory.rb +105 -0
  85. data/lib/mongoid/clients/options.rb +111 -0
  86. data/lib/mongoid/clients/sessions.rb +113 -0
  87. data/lib/mongoid/clients/storage_options.rb +79 -0
  88. data/lib/mongoid/clients/validators/storage.rb +58 -0
  89. data/lib/mongoid/clients/validators.rb +3 -0
  90. data/lib/mongoid/clients.rb +79 -0
  91. data/lib/mongoid/composable.rb +128 -0
  92. data/lib/mongoid/config/environment.rb +51 -13
  93. data/lib/mongoid/config/options.rb +30 -18
  94. data/lib/mongoid/config/validators/client.rb +128 -0
  95. data/lib/mongoid/config/validators/option.rb +3 -4
  96. data/lib/mongoid/config/validators.rb +3 -2
  97. data/lib/mongoid/config.rb +170 -89
  98. data/lib/mongoid/contextual/aggregable/memory.rb +40 -27
  99. data/lib/mongoid/contextual/aggregable/mongo.rb +33 -36
  100. data/lib/mongoid/contextual/aggregable/none.rb +65 -0
  101. data/lib/mongoid/contextual/aggregable.rb +17 -0
  102. data/lib/mongoid/contextual/atomic.rb +80 -79
  103. data/lib/mongoid/contextual/command.rb +8 -11
  104. data/lib/mongoid/contextual/geo_near.rb +42 -44
  105. data/lib/mongoid/contextual/map_reduce.rb +33 -127
  106. data/lib/mongoid/contextual/memory.rb +226 -88
  107. data/lib/mongoid/contextual/mongo.rb +466 -293
  108. data/lib/mongoid/contextual/none.rb +193 -0
  109. data/lib/mongoid/contextual/queryable.rb +3 -4
  110. data/lib/mongoid/contextual.rb +11 -11
  111. data/lib/mongoid/copyable.rb +68 -20
  112. data/lib/mongoid/criteria/findable.rb +143 -0
  113. data/lib/mongoid/criteria/includable.rb +92 -0
  114. data/lib/mongoid/criteria/inspectable.rb +24 -0
  115. data/lib/mongoid/criteria/marshalable.rb +55 -0
  116. data/lib/mongoid/criteria/modifiable.rb +235 -0
  117. data/lib/mongoid/criteria/options.rb +24 -0
  118. data/lib/mongoid/criteria/permission.rb +71 -0
  119. data/lib/mongoid/criteria/queryable/aggregable.rb +109 -0
  120. data/lib/mongoid/criteria/queryable/expandable.rb +68 -0
  121. data/lib/mongoid/criteria/queryable/extensions/array.rb +151 -0
  122. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +57 -0
  123. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +33 -0
  124. data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
  125. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +52 -0
  126. data/lib/mongoid/criteria/queryable/extensions/hash.rb +163 -0
  127. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +75 -0
  128. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +81 -0
  129. data/lib/mongoid/criteria/queryable/extensions/object.rb +182 -0
  130. data/lib/mongoid/criteria/queryable/extensions/range.rb +102 -0
  131. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +72 -0
  132. data/lib/mongoid/criteria/queryable/extensions/set.rb +33 -0
  133. data/lib/mongoid/criteria/queryable/extensions/string.rb +122 -0
  134. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +74 -0
  135. data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
  136. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +66 -0
  137. data/lib/mongoid/criteria/queryable/extensions.rb +25 -0
  138. data/lib/mongoid/criteria/queryable/key.rb +177 -0
  139. data/lib/mongoid/criteria/queryable/macroable.rb +26 -0
  140. data/lib/mongoid/criteria/queryable/mergeable.rb +434 -0
  141. data/lib/mongoid/criteria/queryable/optional.rb +380 -0
  142. data/lib/mongoid/criteria/queryable/options.rb +136 -0
  143. data/lib/mongoid/criteria/queryable/pipeline.rb +106 -0
  144. data/lib/mongoid/criteria/queryable/selectable.rb +937 -0
  145. data/lib/mongoid/criteria/queryable/selector.rb +287 -0
  146. data/lib/mongoid/criteria/queryable/smash.rb +128 -0
  147. data/lib/mongoid/criteria/queryable/storable.rb +237 -0
  148. data/lib/mongoid/criteria/queryable.rb +90 -0
  149. data/lib/mongoid/criteria/scopable.rb +166 -0
  150. data/lib/mongoid/criteria.rb +177 -189
  151. data/lib/mongoid/deprecable.rb +36 -0
  152. data/lib/mongoid/deprecation.rb +25 -0
  153. data/lib/mongoid/document.rb +193 -139
  154. data/lib/mongoid/equality.rb +35 -18
  155. data/lib/mongoid/errors/ambiguous_relationship.rb +5 -6
  156. data/lib/mongoid/errors/callback.rb +2 -3
  157. data/lib/mongoid/errors/criteria_argument_required.rb +18 -0
  158. data/lib/mongoid/errors/delete_restriction.rb +10 -13
  159. data/lib/mongoid/errors/document_not_destroyed.rb +22 -0
  160. data/lib/mongoid/errors/document_not_found.rb +36 -21
  161. data/lib/mongoid/errors/empty_config_file.rb +25 -0
  162. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +19 -0
  163. data/lib/mongoid/errors/invalid_collection.rb +2 -1
  164. data/lib/mongoid/errors/invalid_config_file.rb +25 -0
  165. data/lib/mongoid/errors/invalid_config_option.rb +3 -4
  166. data/lib/mongoid/errors/invalid_dependent_strategy.rb +31 -0
  167. data/lib/mongoid/errors/invalid_discriminator_key_target.rb +24 -0
  168. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  169. data/lib/mongoid/errors/invalid_elem_match_operator.rb +32 -0
  170. data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +25 -0
  171. data/lib/mongoid/errors/invalid_expression_operator.rb +27 -0
  172. data/lib/mongoid/errors/invalid_field.rb +10 -9
  173. data/lib/mongoid/errors/invalid_field_operator.rb +32 -0
  174. data/lib/mongoid/errors/invalid_field_option.rb +2 -3
  175. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  176. data/lib/mongoid/errors/invalid_find.rb +2 -3
  177. data/lib/mongoid/errors/invalid_includes.rb +2 -3
  178. data/lib/mongoid/errors/invalid_index.rb +2 -3
  179. data/lib/mongoid/errors/invalid_options.rb +4 -5
  180. data/lib/mongoid/errors/invalid_path.rb +2 -3
  181. data/lib/mongoid/errors/invalid_persistence_option.rb +26 -0
  182. data/lib/mongoid/errors/invalid_query.rb +40 -0
  183. data/lib/mongoid/errors/invalid_relation.rb +61 -0
  184. data/lib/mongoid/errors/invalid_relation_option.rb +28 -0
  185. data/lib/mongoid/errors/invalid_scope.rb +2 -3
  186. data/lib/mongoid/errors/invalid_session_use.rb +21 -0
  187. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +6 -5
  188. data/lib/mongoid/errors/invalid_storage_options.rb +4 -5
  189. data/lib/mongoid/errors/invalid_storage_parent.rb +25 -0
  190. data/lib/mongoid/errors/invalid_time.rb +2 -3
  191. data/lib/mongoid/errors/inverse_not_found.rb +4 -5
  192. data/lib/mongoid/errors/mixed_client_configuration.rb +27 -0
  193. data/lib/mongoid/errors/mixed_relations.rb +2 -3
  194. data/lib/mongoid/errors/mongoid_error.rb +22 -23
  195. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +3 -4
  196. data/lib/mongoid/errors/no_client_config.rb +21 -0
  197. data/lib/mongoid/errors/no_client_database.rb +26 -0
  198. data/lib/mongoid/errors/no_client_hosts.rb +26 -0
  199. data/lib/mongoid/errors/no_clients_config.rb +19 -0
  200. data/lib/mongoid/errors/no_default_client.rb +22 -0
  201. data/lib/mongoid/errors/no_environment.rb +2 -3
  202. data/lib/mongoid/errors/no_map_reduce_output.rb +2 -3
  203. data/lib/mongoid/errors/no_metadata.rb +2 -3
  204. data/lib/mongoid/errors/no_parent.rb +2 -3
  205. data/lib/mongoid/errors/readonly_attribute.rb +3 -4
  206. data/lib/mongoid/errors/readonly_document.rb +21 -0
  207. data/lib/mongoid/errors/scope_overwrite.rb +2 -1
  208. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +3 -1
  209. data/lib/mongoid/errors/unknown_attribute.rb +3 -4
  210. data/lib/mongoid/errors/unknown_model.rb +24 -0
  211. data/lib/mongoid/errors/unsaved_document.rb +3 -2
  212. data/lib/mongoid/errors/unsupported_javascript.rb +2 -3
  213. data/lib/mongoid/errors/validations.rb +2 -1
  214. data/lib/mongoid/errors.rb +30 -9
  215. data/lib/mongoid/evolvable.rb +4 -5
  216. data/lib/mongoid/extensions/array.rb +45 -52
  217. data/lib/mongoid/extensions/big_decimal.rb +41 -22
  218. data/lib/mongoid/extensions/binary.rb +42 -0
  219. data/lib/mongoid/extensions/boolean.rb +19 -17
  220. data/lib/mongoid/extensions/date.rb +33 -23
  221. data/lib/mongoid/extensions/date_time.rb +5 -13
  222. data/lib/mongoid/extensions/decimal128.rb +36 -0
  223. data/lib/mongoid/extensions/false_class.rb +5 -8
  224. data/lib/mongoid/extensions/float.rb +11 -16
  225. data/lib/mongoid/extensions/hash.rb +88 -49
  226. data/lib/mongoid/extensions/integer.rb +10 -18
  227. data/lib/mongoid/extensions/module.rb +3 -4
  228. data/lib/mongoid/extensions/nil_class.rb +2 -5
  229. data/lib/mongoid/extensions/object.rb +38 -62
  230. data/lib/mongoid/extensions/object_id.rb +7 -12
  231. data/lib/mongoid/extensions/range.rb +46 -17
  232. data/lib/mongoid/extensions/regexp.rb +15 -8
  233. data/lib/mongoid/extensions/set.rb +17 -15
  234. data/lib/mongoid/extensions/string.rb +40 -80
  235. data/lib/mongoid/extensions/symbol.rb +7 -23
  236. data/lib/mongoid/extensions/time.rb +42 -25
  237. data/lib/mongoid/extensions/time_with_zone.rb +27 -10
  238. data/lib/mongoid/extensions/true_class.rb +5 -8
  239. data/lib/mongoid/extensions.rb +31 -13
  240. data/lib/mongoid/factory.rb +99 -11
  241. data/lib/mongoid/fields/foreign_key.rb +26 -34
  242. data/lib/mongoid/fields/localized.rb +24 -13
  243. data/lib/mongoid/fields/standard.rb +19 -73
  244. data/lib/mongoid/fields/validators/macro.rb +56 -15
  245. data/lib/mongoid/fields/validators.rb +2 -1
  246. data/lib/mongoid/fields.rb +342 -87
  247. data/lib/mongoid/findable.rb +219 -0
  248. data/lib/mongoid/indexable/specification.rb +103 -0
  249. data/lib/mongoid/indexable/validators/options.rb +110 -0
  250. data/lib/mongoid/indexable.rb +148 -0
  251. data/lib/mongoid/inspectable.rb +52 -0
  252. data/lib/mongoid/interceptable.rb +312 -0
  253. data/lib/mongoid/loggable.rb +15 -18
  254. data/lib/mongoid/matchable.rb +23 -0
  255. data/lib/mongoid/matcher/all.rb +22 -0
  256. data/lib/mongoid/matcher/and.rb +21 -0
  257. data/lib/mongoid/matcher/bits.rb +41 -0
  258. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  259. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  260. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  261. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  262. data/lib/mongoid/matcher/elem_match.rb +36 -0
  263. data/lib/mongoid/matcher/elem_match_expression.rb +20 -0
  264. data/lib/mongoid/matcher/eq.rb +11 -0
  265. data/lib/mongoid/matcher/eq_impl.rb +67 -0
  266. data/lib/mongoid/matcher/eq_impl_with_regexp.rb +26 -0
  267. data/lib/mongoid/matcher/exists.rb +15 -0
  268. data/lib/mongoid/matcher/expression.rb +35 -0
  269. data/lib/mongoid/matcher/expression_operator.rb +19 -0
  270. data/lib/mongoid/matcher/field_expression.rb +62 -0
  271. data/lib/mongoid/matcher/field_operator.rb +54 -0
  272. data/lib/mongoid/matcher/gt.rb +17 -0
  273. data/lib/mongoid/matcher/gte.rb +17 -0
  274. data/lib/mongoid/matcher/in.rb +25 -0
  275. data/lib/mongoid/matcher/lt.rb +17 -0
  276. data/lib/mongoid/matcher/lte.rb +17 -0
  277. data/lib/mongoid/matcher/mod.rb +17 -0
  278. data/lib/mongoid/matcher/ne.rb +16 -0
  279. data/lib/mongoid/matcher/nin.rb +11 -0
  280. data/lib/mongoid/matcher/nor.rb +25 -0
  281. data/lib/mongoid/matcher/not.rb +29 -0
  282. data/lib/mongoid/matcher/or.rb +21 -0
  283. data/lib/mongoid/matcher/regex.rb +41 -0
  284. data/lib/mongoid/matcher/size.rb +26 -0
  285. data/lib/mongoid/matcher/type.rb +99 -0
  286. data/lib/mongoid/matcher.rb +115 -0
  287. data/lib/mongoid/persistable/creatable.rb +181 -0
  288. data/lib/mongoid/persistable/deletable.rb +132 -0
  289. data/lib/mongoid/persistable/destroyable.rb +57 -0
  290. data/lib/mongoid/persistable/incrementable.rb +35 -0
  291. data/lib/mongoid/persistable/logical.rb +36 -0
  292. data/lib/mongoid/persistable/poppable.rb +36 -0
  293. data/lib/mongoid/persistable/pullable.rb +50 -0
  294. data/lib/mongoid/persistable/pushable.rb +66 -0
  295. data/lib/mongoid/persistable/renamable.rb +37 -0
  296. data/lib/mongoid/persistable/savable.rb +47 -0
  297. data/lib/mongoid/persistable/settable.rb +93 -0
  298. data/lib/mongoid/persistable/unsettable.rb +36 -0
  299. data/lib/mongoid/persistable/updatable.rb +165 -0
  300. data/lib/mongoid/persistable/upsertable.rb +51 -0
  301. data/lib/mongoid/persistable.rb +305 -0
  302. data/lib/mongoid/persistence_context.rb +239 -0
  303. data/lib/mongoid/positional.rb +72 -0
  304. data/lib/mongoid/query_cache.rb +64 -0
  305. data/lib/mongoid/railtie.rb +35 -78
  306. data/lib/mongoid/railties/controller_runtime.rb +88 -0
  307. data/lib/mongoid/railties/database.rake +18 -25
  308. data/lib/mongoid/reloadable.rb +94 -0
  309. data/lib/mongoid/scopable.rb +324 -0
  310. data/lib/mongoid/selectable.rb +49 -0
  311. data/lib/mongoid/serializable.rb +170 -0
  312. data/lib/mongoid/shardable.rb +130 -0
  313. data/lib/mongoid/stateful.rb +134 -0
  314. data/lib/mongoid/stringified_symbol.rb +52 -0
  315. data/lib/mongoid/tasks/database.rake +38 -0
  316. data/lib/mongoid/tasks/database.rb +194 -0
  317. data/lib/mongoid/threaded/lifecycle.rb +28 -70
  318. data/lib/mongoid/threaded.rb +142 -219
  319. data/lib/mongoid/timestamps/created/short.rb +2 -1
  320. data/lib/mongoid/timestamps/created.rb +9 -5
  321. data/lib/mongoid/timestamps/short.rb +2 -1
  322. data/lib/mongoid/timestamps/timeless.rb +52 -16
  323. data/lib/mongoid/timestamps/updated/short.rb +4 -3
  324. data/lib/mongoid/timestamps/updated.rb +14 -9
  325. data/lib/mongoid/timestamps.rb +4 -3
  326. data/lib/mongoid/touchable.rb +131 -0
  327. data/lib/mongoid/traversable.rb +337 -0
  328. data/lib/mongoid/validatable/associated.rb +47 -0
  329. data/lib/mongoid/validatable/format.rb +21 -0
  330. data/lib/mongoid/validatable/length.rb +21 -0
  331. data/lib/mongoid/validatable/localizable.rb +29 -0
  332. data/lib/mongoid/validatable/macros.rb +89 -0
  333. data/lib/mongoid/validatable/presence.rb +81 -0
  334. data/lib/mongoid/validatable/queryable.rb +29 -0
  335. data/lib/mongoid/validatable/uniqueness.rb +304 -0
  336. data/lib/mongoid/validatable.rb +160 -0
  337. data/lib/mongoid/version.rb +3 -2
  338. data/lib/mongoid/warnings.rb +28 -0
  339. data/lib/mongoid.rb +68 -109
  340. data/lib/rails/generators/mongoid/config/config_generator.rb +10 -2
  341. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +150 -45
  342. data/lib/rails/generators/mongoid/model/model_generator.rb +3 -3
  343. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -4
  344. data/lib/rails/generators/mongoid_generator.rb +5 -41
  345. data/lib/rails/mongoid.rb +6 -129
  346. data/spec/README.md +33 -0
  347. data/spec/config/mongoid.yml +56 -25
  348. data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
  349. data/spec/integration/app_spec.rb +345 -0
  350. data/spec/integration/associations/belongs_to_spec.rb +33 -0
  351. data/spec/integration/associations/embedded_dirty_spec.rb +57 -0
  352. data/spec/integration/associations/embedded_spec.rb +283 -0
  353. data/spec/integration/associations/embeds_many_spec.rb +219 -0
  354. data/spec/integration/associations/embeds_one_spec.rb +41 -0
  355. data/spec/integration/associations/foreign_key_spec.rb +107 -0
  356. data/spec/integration/associations/foreign_key_spec_models.rb +64 -0
  357. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  358. data/spec/integration/associations/has_many_spec.rb +128 -0
  359. data/spec/integration/associations/has_one_spec.rb +272 -0
  360. data/spec/integration/associations/nested_attributes_assignment_spec.rb +115 -0
  361. data/spec/integration/associations/reverse_population_spec.rb +34 -0
  362. data/spec/integration/associations/reverse_population_spec_models.rb +36 -0
  363. data/spec/integration/associations/scope_option_spec.rb +101 -0
  364. data/spec/integration/atomic/modifiers_spec.rb +116 -0
  365. data/spec/integration/bson_regexp_raw_spec.rb +19 -0
  366. data/spec/integration/callbacks_models.rb +155 -0
  367. data/spec/integration/callbacks_spec.rb +450 -0
  368. data/spec/integration/contextual/empty_spec.rb +141 -0
  369. data/spec/integration/criteria/alias_query_spec.rb +161 -0
  370. data/spec/integration/criteria/date_field_spec.rb +40 -0
  371. data/spec/integration/criteria/default_scope_spec.rb +72 -0
  372. data/spec/integration/criteria/logical_spec.rb +124 -0
  373. data/spec/integration/criteria/range_spec.rb +359 -0
  374. data/spec/integration/criteria/time_with_zone_spec.rb +142 -0
  375. data/spec/integration/discriminator_key_spec.rb +392 -0
  376. data/spec/integration/discriminator_value_spec.rb +206 -0
  377. data/spec/integration/document_spec.rb +51 -0
  378. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  379. data/spec/integration/i18n_fallbacks_spec.rb +89 -0
  380. data/spec/integration/matcher_examples_spec.rb +765 -0
  381. data/spec/integration/matcher_operator_data/all.yml +140 -0
  382. data/spec/integration/matcher_operator_data/and.yml +93 -0
  383. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  384. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  385. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  386. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  387. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  388. data/spec/integration/matcher_operator_data/elem_match.yml +409 -0
  389. data/spec/integration/matcher_operator_data/elem_match_expr.yml +213 -0
  390. data/spec/integration/matcher_operator_data/eq.yml +191 -0
  391. data/spec/integration/matcher_operator_data/exists.yml +213 -0
  392. data/spec/integration/matcher_operator_data/generic_op.yml +17 -0
  393. data/spec/integration/matcher_operator_data/gt.yml +132 -0
  394. data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
  395. data/spec/integration/matcher_operator_data/gte.yml +132 -0
  396. data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
  397. data/spec/integration/matcher_operator_data/implicit.yml +331 -0
  398. data/spec/integration/matcher_operator_data/implicit_traversal.yml +112 -0
  399. data/spec/integration/matcher_operator_data/in.yml +210 -0
  400. data/spec/integration/matcher_operator_data/invalid_op.yml +59 -0
  401. data/spec/integration/matcher_operator_data/invalid_syntax.yml +39 -0
  402. data/spec/integration/matcher_operator_data/lt.yml +132 -0
  403. data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
  404. data/spec/integration/matcher_operator_data/lte.yml +132 -0
  405. data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
  406. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  407. data/spec/integration/matcher_operator_data/multiple.yml +29 -0
  408. data/spec/integration/matcher_operator_data/ne.yml +150 -0
  409. data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
  410. data/spec/integration/matcher_operator_data/nin.yml +114 -0
  411. data/spec/integration/matcher_operator_data/nor.yml +126 -0
  412. data/spec/integration/matcher_operator_data/not.yml +196 -0
  413. data/spec/integration/matcher_operator_data/or.yml +137 -0
  414. data/spec/integration/matcher_operator_data/regex.yml +174 -0
  415. data/spec/integration/matcher_operator_data/regex_options.yml +72 -0
  416. data/spec/integration/matcher_operator_data/size.yml +174 -0
  417. data/spec/integration/matcher_operator_data/type.yml +70 -0
  418. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  419. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  420. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  421. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  422. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  423. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  424. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  425. data/spec/integration/matcher_operator_data/type_decimal.yml +41 -0
  426. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  427. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  428. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  429. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  430. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  431. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  432. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  433. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  434. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  435. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  436. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  437. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  438. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  439. data/spec/integration/matcher_operator_spec.rb +122 -0
  440. data/spec/integration/matcher_spec.rb +283 -0
  441. data/spec/integration/persistence/range_field_spec.rb +350 -0
  442. data/spec/integration/server_query_spec.rb +141 -0
  443. data/spec/integration/shardable_spec.rb +148 -0
  444. data/spec/integration/stringified_symbol_field_spec.rb +203 -0
  445. data/spec/lite_spec_helper.rb +83 -0
  446. data/spec/mongoid/association/accessors_spec.rb +1067 -0
  447. data/spec/mongoid/association/auto_save_spec.rb +403 -0
  448. data/spec/mongoid/association/builders_spec.rb +255 -0
  449. data/spec/mongoid/association/constrainable_spec.rb +117 -0
  450. data/spec/mongoid/association/counter_cache_spec.rb +452 -0
  451. data/spec/mongoid/association/depending_spec.rb +959 -0
  452. data/spec/mongoid/association/eager_spec.rb +282 -0
  453. data/spec/mongoid/association/embedded/cyclic_spec.rb +180 -0
  454. data/spec/mongoid/association/embedded/dirty_spec.rb +67 -0
  455. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +174 -0
  456. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +90 -0
  457. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +619 -0
  458. data/spec/mongoid/association/embedded/embedded_in_spec.rb +903 -0
  459. data/spec/mongoid/association/embedded/embeds_many/binding_spec.rb +56 -0
  460. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +218 -0
  461. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +4863 -0
  462. data/spec/mongoid/association/embedded/embeds_many_models.rb +226 -0
  463. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +63 -0
  464. data/spec/mongoid/association/embedded/embeds_many_spec.rb +932 -0
  465. data/spec/mongoid/association/embedded/embeds_one/binding_spec.rb +79 -0
  466. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +106 -0
  467. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +1025 -0
  468. data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +8 -0
  469. data/spec/mongoid/association/embedded/embeds_one_models.rb +73 -0
  470. data/spec/mongoid/association/embedded/embeds_one_query_spec.rb +28 -0
  471. data/spec/mongoid/association/embedded/embeds_one_spec.rb +984 -0
  472. data/spec/mongoid/association/macros_spec.rb +1116 -0
  473. data/spec/mongoid/association/nested/many_spec.rb +232 -0
  474. data/spec/mongoid/association/nested/one_spec.rb +253 -0
  475. data/spec/mongoid/association/options_spec.rb +1323 -0
  476. data/spec/mongoid/association/polymorphic_spec.rb +162 -0
  477. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +244 -0
  478. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +292 -0
  479. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +412 -0
  480. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +1388 -0
  481. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  482. data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +57 -0
  483. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2046 -0
  484. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +180 -0
  485. data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +148 -0
  486. data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +196 -0
  487. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +76 -0
  488. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +3836 -0
  489. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +92 -0
  490. data/spec/mongoid/association/referenced/has_and_belongs_to_many_query_spec.rb +39 -0
  491. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +1104 -0
  492. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +155 -0
  493. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +251 -0
  494. data/spec/mongoid/association/referenced/has_many/eager_spec.rb +290 -0
  495. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2232 -0
  496. data/spec/mongoid/association/referenced/has_many/proxy_query_spec.rb +23 -0
  497. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +4161 -0
  498. data/spec/mongoid/association/referenced/has_many_models.rb +97 -0
  499. data/spec/mongoid/association/referenced/has_many_query_spec.rb +37 -0
  500. data/spec/mongoid/association/referenced/has_many_spec.rb +1273 -0
  501. data/spec/mongoid/association/referenced/has_one/binding_spec.rb +133 -0
  502. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +159 -0
  503. data/spec/mongoid/association/referenced/has_one/eager_spec.rb +193 -0
  504. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +1248 -0
  505. data/spec/mongoid/association/referenced/has_one_models.rb +113 -0
  506. data/spec/mongoid/association/referenced/has_one_query_spec.rb +37 -0
  507. data/spec/mongoid/association/referenced/has_one_spec.rb +1383 -0
  508. data/spec/mongoid/association/reflections_spec.rb +92 -0
  509. data/spec/mongoid/association/syncable_spec.rb +513 -0
  510. data/spec/mongoid/association_spec.rb +191 -0
  511. data/spec/mongoid/atomic/modifiers_spec.rb +88 -39
  512. data/spec/mongoid/atomic/paths/embedded/many_spec.rb +10 -49
  513. data/spec/mongoid/atomic/paths/embedded/one_spec.rb +9 -49
  514. data/spec/mongoid/atomic/paths/root_spec.rb +5 -61
  515. data/spec/mongoid/atomic/paths_spec.rb +115 -35
  516. data/spec/mongoid/atomic_spec.rb +89 -42
  517. data/spec/mongoid/attributes/dynamic_spec.rb +152 -0
  518. data/spec/mongoid/attributes/nested_spec.rb +5000 -0
  519. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  520. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  521. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  522. data/spec/mongoid/attributes/projector_spec.rb +40 -0
  523. data/spec/mongoid/attributes/readonly_spec.rb +166 -64
  524. data/spec/mongoid/attributes_spec.rb +1418 -409
  525. data/spec/mongoid/cacheable_spec.rb +114 -0
  526. data/spec/mongoid/changeable_spec.rb +1914 -0
  527. data/spec/mongoid/clients/factory_spec.rb +426 -0
  528. data/spec/mongoid/clients/options_spec.rb +521 -0
  529. data/spec/mongoid/clients/sessions_spec.rb +297 -0
  530. data/spec/mongoid/clients/transactions_spec.rb +415 -0
  531. data/spec/mongoid/clients_spec.rb +1084 -0
  532. data/spec/mongoid/composable_spec.rb +33 -0
  533. data/spec/mongoid/config/environment_spec.rb +138 -17
  534. data/spec/mongoid/config/options_spec.rb +26 -7
  535. data/spec/mongoid/config_spec.rb +607 -93
  536. data/spec/mongoid/contextual/aggregable/memory_spec.rb +433 -153
  537. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  538. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  539. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +221 -56
  540. data/spec/mongoid/contextual/aggregable/none_spec.rb +60 -0
  541. data/spec/mongoid/contextual/atomic_spec.rb +577 -162
  542. data/spec/mongoid/contextual/geo_near_spec.rb +104 -38
  543. data/spec/mongoid/contextual/map_reduce_spec.rb +137 -142
  544. data/spec/mongoid/contextual/memory_spec.rb +1880 -269
  545. data/spec/mongoid/contextual/mongo_spec.rb +2523 -601
  546. data/spec/mongoid/contextual/none_spec.rb +123 -0
  547. data/spec/mongoid/copyable_spec.rb +833 -76
  548. data/spec/mongoid/copyable_spec_models.rb +47 -0
  549. data/spec/mongoid/criteria/findable_spec.rb +1132 -0
  550. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  551. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  552. data/spec/mongoid/criteria/inspectable_spec.rb +29 -0
  553. data/spec/mongoid/criteria/marshalable_spec.rb +47 -0
  554. data/spec/mongoid/criteria/modifiable_spec.rb +1812 -0
  555. data/spec/mongoid/criteria/options_spec.rb +31 -0
  556. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +372 -0
  557. data/spec/mongoid/criteria/queryable/expandable_spec.rb +61 -0
  558. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +513 -0
  559. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +169 -0
  560. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +60 -0
  561. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +215 -0
  562. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +343 -0
  563. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +434 -0
  564. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +60 -0
  565. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +67 -0
  566. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +314 -0
  567. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +67 -0
  568. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +79 -0
  569. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +119 -0
  570. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +110 -0
  571. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +370 -0
  572. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +91 -0
  573. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +92 -0
  574. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +41 -0
  575. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +347 -0
  576. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +169 -0
  577. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +406 -0
  578. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +387 -0
  579. data/spec/mongoid/criteria/queryable/key_spec.rb +96 -0
  580. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +182 -0
  581. data/spec/mongoid/criteria/queryable/optional_spec.rb +1317 -0
  582. data/spec/mongoid/criteria/queryable/options_spec.rb +362 -0
  583. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +214 -0
  584. data/spec/mongoid/criteria/queryable/queryable_spec.rb +139 -0
  585. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +2119 -0
  586. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +38 -0
  587. data/spec/mongoid/criteria/queryable/selectable_spec.rb +2462 -0
  588. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +589 -0
  589. data/spec/mongoid/criteria/queryable/selector_spec.rb +895 -0
  590. data/spec/mongoid/criteria/queryable/smash_spec.rb +32 -0
  591. data/spec/mongoid/criteria/queryable/storable_spec.rb +226 -0
  592. data/spec/mongoid/criteria/scopable_spec.rb +601 -0
  593. data/spec/mongoid/criteria_projection_spec.rb +410 -0
  594. data/spec/mongoid/criteria_spec.rb +1828 -3572
  595. data/spec/mongoid/document_fields_spec.rb +262 -0
  596. data/spec/mongoid/document_persistence_context_spec.rb +32 -0
  597. data/spec/mongoid/document_query_spec.rb +89 -0
  598. data/spec/mongoid/document_spec.rb +452 -221
  599. data/spec/mongoid/equality_spec.rb +155 -52
  600. data/spec/mongoid/errors/ambiguous_relationship_spec.rb +8 -6
  601. data/spec/mongoid/errors/callback_spec.rb +5 -3
  602. data/spec/mongoid/errors/delete_restriction_spec.rb +7 -5
  603. data/spec/mongoid/errors/document_not_destroyed_spec.rb +35 -0
  604. data/spec/mongoid/errors/document_not_found_spec.rb +89 -11
  605. data/spec/mongoid/errors/invalid_collection_spec.rb +5 -3
  606. data/spec/mongoid/errors/invalid_config_file_spec.rb +31 -0
  607. data/spec/mongoid/errors/invalid_config_option_spec.rb +5 -3
  608. data/spec/mongoid/errors/invalid_field_option_spec.rb +5 -3
  609. data/spec/mongoid/errors/invalid_field_spec.rb +6 -4
  610. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  611. data/spec/mongoid/errors/invalid_find_spec.rb +5 -3
  612. data/spec/mongoid/errors/invalid_includes_spec.rb +5 -3
  613. data/spec/mongoid/errors/invalid_index_spec.rb +5 -3
  614. data/spec/mongoid/errors/invalid_options_spec.rb +7 -5
  615. data/spec/mongoid/errors/invalid_path_spec.rb +5 -3
  616. data/spec/mongoid/errors/invalid_relation_spec.rb +39 -0
  617. data/spec/mongoid/errors/invalid_scope_spec.rb +7 -5
  618. data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +5 -3
  619. data/spec/mongoid/errors/invalid_storage_options_spec.rb +5 -3
  620. data/spec/mongoid/errors/invalid_time_spec.rb +5 -3
  621. data/spec/mongoid/errors/inverse_not_found_spec.rb +6 -4
  622. data/spec/mongoid/errors/mixed_client_configuration_spec.rb +31 -0
  623. data/spec/mongoid/errors/mixed_relations_spec.rb +5 -3
  624. data/spec/mongoid/errors/mongoid_error_spec.rb +45 -10
  625. data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +8 -6
  626. data/spec/mongoid/errors/no_client_config_spec.rb +31 -0
  627. data/spec/mongoid/errors/no_client_database_spec.rb +31 -0
  628. data/spec/mongoid/errors/no_client_hosts_spec.rb +31 -0
  629. data/spec/mongoid/errors/no_clients_config_spec.rb +31 -0
  630. data/spec/mongoid/errors/no_environment_spec.rb +8 -6
  631. data/spec/mongoid/errors/no_map_reduce_output_spec.rb +5 -3
  632. data/spec/mongoid/errors/no_metadata_spec.rb +5 -3
  633. data/spec/mongoid/errors/no_parent_spec.rb +6 -4
  634. data/spec/mongoid/errors/readonly_attribute_spec.rb +5 -3
  635. data/spec/mongoid/errors/readonly_document_spec.rb +31 -0
  636. data/spec/mongoid/errors/scope_overwrite_spec.rb +5 -3
  637. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +6 -4
  638. data/spec/mongoid/errors/unknown_attribute_spec.rb +7 -5
  639. data/spec/mongoid/errors/unsaved_document_spec.rb +6 -4
  640. data/spec/mongoid/errors/unsupported_javascript_spec.rb +5 -3
  641. data/spec/mongoid/errors/validations_spec.rb +9 -7
  642. data/spec/mongoid/extensions/array_spec.rb +108 -116
  643. data/spec/mongoid/extensions/big_decimal_spec.rb +838 -49
  644. data/spec/mongoid/extensions/binary_spec.rb +55 -18
  645. data/spec/mongoid/extensions/boolean_spec.rb +76 -74
  646. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +339 -0
  647. data/spec/mongoid/extensions/date_spec.rb +59 -145
  648. data/spec/mongoid/extensions/date_time_spec.rb +35 -76
  649. data/spec/mongoid/extensions/decimal128_spec.rb +46 -0
  650. data/spec/mongoid/extensions/false_class_spec.rb +7 -5
  651. data/spec/mongoid/extensions/float_spec.rb +69 -62
  652. data/spec/mongoid/extensions/hash_spec.rb +197 -30
  653. data/spec/mongoid/extensions/integer_spec.rb +63 -65
  654. data/spec/mongoid/extensions/module_spec.rb +4 -2
  655. data/spec/mongoid/extensions/nil_class_spec.rb +3 -1
  656. data/spec/mongoid/extensions/object_id_spec.rb +136 -134
  657. data/spec/mongoid/extensions/object_spec.rb +53 -57
  658. data/spec/mongoid/extensions/range_spec.rb +287 -28
  659. data/spec/mongoid/extensions/regexp_spec.rb +71 -21
  660. data/spec/mongoid/extensions/set_spec.rb +112 -4
  661. data/spec/mongoid/extensions/string_spec.rb +188 -89
  662. data/spec/mongoid/extensions/stringified_symbol_spec.rb +84 -0
  663. data/spec/mongoid/extensions/symbol_spec.rb +25 -30
  664. data/spec/mongoid/extensions/time_spec.rb +703 -110
  665. data/spec/mongoid/extensions/time_with_zone_spec.rb +82 -67
  666. data/spec/mongoid/extensions/true_class_spec.rb +7 -5
  667. data/spec/mongoid/extensions_spec.rb +43 -0
  668. data/spec/mongoid/factory_spec.rb +374 -25
  669. data/spec/mongoid/fields/foreign_key_spec.rb +116 -92
  670. data/spec/mongoid/fields/localized_spec.rb +177 -35
  671. data/spec/mongoid/fields/standard_spec.rb +15 -13
  672. data/spec/mongoid/fields_spec.rb +952 -238
  673. data/spec/mongoid/findable_spec.rb +632 -0
  674. data/spec/mongoid/indexable/specification_spec.rb +129 -0
  675. data/spec/mongoid/indexable_spec.rb +643 -0
  676. data/spec/mongoid/inspectable_spec.rb +86 -0
  677. data/spec/mongoid/interceptable_spec.rb +2373 -0
  678. data/spec/mongoid/interceptable_spec_models.rb +307 -0
  679. data/spec/mongoid/loggable_spec.rb +3 -1
  680. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  681. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +239 -0
  682. data/spec/mongoid/matcher/extract_attribute_spec.rb +36 -0
  683. data/spec/mongoid/mongoizable_spec.rb +285 -0
  684. data/spec/mongoid/persistable/creatable_spec.rb +662 -0
  685. data/spec/mongoid/persistable/deletable_spec.rb +514 -0
  686. data/spec/mongoid/persistable/destroyable_spec.rb +455 -0
  687. data/spec/mongoid/persistable/incrementable_spec.rb +241 -0
  688. data/spec/mongoid/persistable/logical_spec.rb +159 -0
  689. data/spec/mongoid/persistable/poppable_spec.rb +131 -0
  690. data/spec/mongoid/persistable/pullable_spec.rb +258 -0
  691. data/spec/mongoid/persistable/pushable_spec.rb +353 -0
  692. data/spec/mongoid/persistable/renamable_spec.rb +151 -0
  693. data/spec/mongoid/persistable/savable_spec.rb +684 -0
  694. data/spec/mongoid/persistable/settable_spec.rb +544 -0
  695. data/spec/mongoid/persistable/unsettable_spec.rb +171 -0
  696. data/spec/mongoid/persistable/updatable_spec.rb +760 -0
  697. data/spec/mongoid/persistable/upsertable_spec.rb +122 -0
  698. data/spec/mongoid/persistable_spec.rb +321 -0
  699. data/spec/mongoid/persistence_context_spec.rb +745 -0
  700. data/spec/mongoid/positional_spec.rb +223 -0
  701. data/spec/mongoid/query_cache_middleware_spec.rb +50 -0
  702. data/spec/mongoid/query_cache_spec.rb +870 -0
  703. data/spec/mongoid/relations/proxy_spec.rb +125 -47
  704. data/spec/mongoid/reloadable_spec.rb +665 -0
  705. data/spec/mongoid/scopable_spec.rb +1234 -0
  706. data/spec/mongoid/selectable_spec.rb +136 -0
  707. data/spec/mongoid/serializable_spec.rb +963 -0
  708. data/spec/mongoid/shardable_models.rb +61 -0
  709. data/spec/mongoid/shardable_spec.rb +204 -0
  710. data/spec/mongoid/stateful_spec.rb +157 -0
  711. data/spec/mongoid/tasks/database_rake_spec.rb +287 -0
  712. data/spec/mongoid/tasks/database_spec.rb +181 -0
  713. data/spec/mongoid/threaded_spec.rb +88 -78
  714. data/spec/mongoid/timestamps/created/short_spec.rb +9 -7
  715. data/spec/mongoid/timestamps/created_spec.rb +8 -6
  716. data/spec/mongoid/timestamps/timeless_spec.rb +29 -10
  717. data/spec/mongoid/timestamps/updated/short_spec.rb +16 -14
  718. data/spec/mongoid/timestamps/updated_spec.rb +14 -16
  719. data/spec/mongoid/timestamps_spec.rb +406 -18
  720. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  721. data/spec/mongoid/touchable_spec.rb +704 -0
  722. data/spec/mongoid/touchable_spec_models.rb +57 -0
  723. data/spec/mongoid/traversable_spec.rb +1410 -0
  724. data/spec/mongoid/validatable/associated_spec.rb +208 -0
  725. data/spec/mongoid/validatable/format_spec.rb +85 -0
  726. data/spec/mongoid/validatable/length_spec.rb +225 -0
  727. data/spec/mongoid/validatable/numericality_spec.rb +32 -0
  728. data/spec/mongoid/validatable/presence_spec.rb +592 -0
  729. data/spec/mongoid/validatable/uniqueness_spec.rb +2504 -0
  730. data/spec/mongoid/validatable_spec.rb +327 -0
  731. data/spec/mongoid/warnings_spec.rb +35 -0
  732. data/spec/mongoid_spec.rb +20 -20
  733. data/spec/rails/controller_extension/controller_runtime_spec.rb +112 -0
  734. data/spec/rails/mongoid_spec.rb +37 -354
  735. data/spec/shared/LICENSE +20 -0
  736. data/spec/shared/bin/get-mongodb-download-url +17 -0
  737. data/spec/shared/bin/s3-copy +45 -0
  738. data/spec/shared/bin/s3-upload +69 -0
  739. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  740. data/spec/shared/lib/mrss/cluster_config.rb +231 -0
  741. data/spec/shared/lib/mrss/constraints.rb +378 -0
  742. data/spec/shared/lib/mrss/docker_runner.rb +291 -0
  743. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  744. data/spec/shared/lib/mrss/event_subscriber.rb +200 -0
  745. data/spec/shared/lib/mrss/lite_constraints.rb +230 -0
  746. data/spec/shared/lib/mrss/server_version_registry.rb +120 -0
  747. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  748. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  749. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  750. data/spec/shared/lib/mrss/utils.rb +15 -0
  751. data/spec/shared/share/Dockerfile.erb +325 -0
  752. data/spec/shared/share/haproxy-1.conf +16 -0
  753. data/spec/shared/share/haproxy-2.conf +17 -0
  754. data/spec/shared/shlib/config.sh +27 -0
  755. data/spec/shared/shlib/distro.sh +74 -0
  756. data/spec/shared/shlib/server.sh +392 -0
  757. data/spec/shared/shlib/set_env.sh +169 -0
  758. data/spec/spec_helper.rb +163 -42
  759. data/spec/support/authorization.rb +15 -0
  760. data/spec/support/client_registry.rb +9 -0
  761. data/spec/support/constraints.rb +77 -0
  762. data/spec/support/expectations.rb +32 -0
  763. data/spec/support/helpers.rb +11 -0
  764. data/spec/support/macros.rb +81 -0
  765. data/spec/support/models/account.rb +38 -0
  766. data/spec/support/models/acolyte.rb +19 -0
  767. data/spec/support/models/actor.rb +20 -0
  768. data/spec/support/models/actress.rb +4 -0
  769. data/spec/support/models/address.rb +85 -0
  770. data/spec/support/models/address_component.rb +7 -0
  771. data/spec/support/models/address_number.rb +8 -0
  772. data/spec/support/models/agency.rb +7 -0
  773. data/spec/support/models/agent.rb +18 -0
  774. data/spec/support/models/album.rb +20 -0
  775. data/spec/support/models/alert.rb +9 -0
  776. data/spec/support/models/animal.rb +28 -0
  777. data/spec/support/models/answer.rb +8 -0
  778. data/spec/support/models/appointment.rb +9 -0
  779. data/spec/support/models/armrest.rb +9 -0
  780. data/spec/support/models/array_field.rb +7 -0
  781. data/spec/support/models/article.rb +14 -0
  782. data/spec/support/models/artist.rb +91 -0
  783. data/spec/support/models/artwork.rb +6 -0
  784. data/spec/support/models/audible_sound.rb +3 -0
  785. data/spec/support/models/audio.rb +7 -0
  786. data/spec/support/models/augmentation.rb +25 -0
  787. data/spec/support/models/author.rb +8 -0
  788. data/spec/support/models/baby.rb +6 -0
  789. data/spec/support/models/band.rb +40 -0
  790. data/spec/support/models/bar.rb +12 -0
  791. data/spec/support/models/basic.rb +8 -0
  792. data/spec/support/models/bed.rb +3 -0
  793. data/spec/support/models/big_palette.rb +4 -0
  794. data/spec/support/models/birthday.rb +15 -0
  795. data/spec/support/models/bolt.rb +7 -0
  796. data/spec/support/models/bomb.rb +6 -0
  797. data/spec/support/models/book.rb +18 -0
  798. data/spec/support/models/breed.rb +6 -0
  799. data/spec/support/models/browser.rb +8 -0
  800. data/spec/support/models/building.rb +8 -0
  801. data/spec/support/models/building_address.rb +9 -0
  802. data/spec/support/models/bus.rb +9 -0
  803. data/spec/support/models/business.rb +7 -0
  804. data/spec/support/models/callback_test.rb +11 -0
  805. data/spec/support/models/canvas.rb +27 -0
  806. data/spec/support/models/car.rb +3 -0
  807. data/spec/support/models/cat.rb +10 -0
  808. data/spec/support/models/catalog.rb +24 -0
  809. data/spec/support/models/category.rb +10 -0
  810. data/spec/support/models/child.rb +6 -0
  811. data/spec/support/models/child_doc.rb +24 -0
  812. data/spec/support/models/church.rb +8 -0
  813. data/spec/support/models/circle.rb +5 -0
  814. data/spec/support/models/circuit.rb +6 -0
  815. data/spec/support/models/circus.rb +12 -0
  816. data/spec/support/models/code.rb +15 -0
  817. data/spec/support/models/coding/pull_request.rb +11 -0
  818. data/spec/support/models/coding.rb +3 -0
  819. data/spec/support/models/comment.rb +18 -0
  820. data/spec/support/models/company.rb +7 -0
  821. data/spec/support/models/consumption_period.rb +9 -0
  822. data/spec/support/models/contextable_item.rb +7 -0
  823. data/spec/support/models/contractor.rb +7 -0
  824. data/spec/support/models/cookie.rb +8 -0
  825. data/spec/support/models/country_code.rb +12 -0
  826. data/spec/support/models/courier_job.rb +6 -0
  827. data/spec/support/models/crate.rb +12 -0
  828. data/spec/support/models/customer.rb +10 -0
  829. data/spec/support/models/customer_address.rb +11 -0
  830. data/spec/support/models/deed.rb +7 -0
  831. data/spec/support/models/definition.rb +11 -0
  832. data/spec/support/models/delegating_patient.rb +15 -0
  833. data/spec/support/models/description.rb +13 -0
  834. data/spec/support/models/dictionary.rb +18 -0
  835. data/spec/support/models/division.rb +12 -0
  836. data/spec/support/models/doctor.rb +14 -0
  837. data/spec/support/models/dog.rb +9 -0
  838. data/spec/support/models/dokument.rb +8 -0
  839. data/spec/support/models/draft.rb +11 -0
  840. data/spec/support/models/dragon.rb +6 -0
  841. data/spec/support/models/driver.rb +9 -0
  842. data/spec/support/models/drug.rb +8 -0
  843. data/spec/support/models/dungeon.rb +6 -0
  844. data/spec/support/models/edit.rb +7 -0
  845. data/spec/support/models/email.rb +8 -0
  846. data/spec/support/models/employer.rb +7 -0
  847. data/spec/support/models/entry.rb +8 -0
  848. data/spec/support/models/eraser.rb +3 -0
  849. data/spec/support/models/even.rb +9 -0
  850. data/spec/support/models/event.rb +24 -0
  851. data/spec/support/models/exhibition.rb +6 -0
  852. data/spec/support/models/exhibitor.rb +8 -0
  853. data/spec/support/models/explosion.rb +6 -0
  854. data/spec/support/models/eye.rb +11 -0
  855. data/spec/support/models/eye_bowl.rb +11 -0
  856. data/spec/support/models/face.rb +10 -0
  857. data/spec/support/models/fanatic.rb +8 -0
  858. data/spec/support/models/favorite.rb +8 -0
  859. data/spec/support/models/filesystem.rb +7 -0
  860. data/spec/support/models/fire_hydrant.rb +8 -0
  861. data/spec/support/models/firefox.rb +6 -0
  862. data/spec/support/models/fish.rb +9 -0
  863. data/spec/support/models/folder.rb +9 -0
  864. data/spec/support/models/folder_item.rb +11 -0
  865. data/spec/support/models/fruits.rb +36 -0
  866. data/spec/support/models/game.rb +21 -0
  867. data/spec/support/models/ghost.rb +9 -0
  868. data/spec/support/models/guitar.rb +4 -0
  869. data/spec/support/models/hole.rb +12 -0
  870. data/spec/support/models/home.rb +6 -0
  871. data/spec/support/models/house.rb +8 -0
  872. data/spec/support/models/html_writer.rb +5 -0
  873. data/spec/support/models/id_key.rb +8 -0
  874. data/spec/support/models/idnodef.rb +7 -0
  875. data/spec/support/models/image.rb +24 -0
  876. data/spec/support/models/implant.rb +27 -0
  877. data/spec/support/models/instrument.rb +8 -0
  878. data/spec/support/models/item.rb +10 -0
  879. data/spec/support/models/jar.rb +9 -0
  880. data/spec/support/models/kaleidoscope.rb +8 -0
  881. data/spec/support/models/kangaroo.rb +6 -0
  882. data/spec/support/models/label.rb +52 -0
  883. data/spec/support/models/language.rb +7 -0
  884. data/spec/support/models/lat_lng.rb +17 -0
  885. data/spec/support/models/league.rb +13 -0
  886. data/spec/support/models/learner.rb +4 -0
  887. data/spec/support/models/line_item.rb +8 -0
  888. data/spec/support/models/location.rb +10 -0
  889. data/spec/support/models/login.rb +10 -0
  890. data/spec/support/models/manufacturer.rb +9 -0
  891. data/spec/support/models/meat.rb +6 -0
  892. data/spec/support/models/membership.rb +7 -0
  893. data/spec/support/models/message.rb +13 -0
  894. data/spec/support/models/minim.rb +6 -0
  895. data/spec/support/models/mixed_drink.rb +6 -0
  896. data/spec/support/models/mop.rb +24 -0
  897. data/spec/support/models/movie.rb +15 -0
  898. data/spec/support/models/my_hash.rb +4 -0
  899. data/spec/support/models/name.rb +26 -0
  900. data/spec/support/models/name_only.rb +8 -0
  901. data/spec/support/models/node.rb +7 -0
  902. data/spec/support/models/note.rb +19 -0
  903. data/spec/support/models/nut.rb +7 -0
  904. data/spec/support/models/odd.rb +9 -0
  905. data/spec/support/models/order.rb +12 -0
  906. data/spec/support/models/ordered_post.rb +13 -0
  907. data/spec/support/models/ordered_preference.rb +8 -0
  908. data/spec/support/models/oscar.rb +16 -0
  909. data/spec/support/models/other_owner_object.rb +4 -0
  910. data/spec/support/models/override.rb +18 -0
  911. data/spec/support/models/ownable.rb +8 -0
  912. data/spec/support/models/owner.rb +10 -0
  913. data/spec/support/models/pack.rb +5 -0
  914. data/spec/support/models/page.rb +18 -0
  915. data/spec/support/models/page_question.rb +6 -0
  916. data/spec/support/models/palette.rb +9 -0
  917. data/spec/support/models/parent.rb +7 -0
  918. data/spec/support/models/parent_doc.rb +8 -0
  919. data/spec/support/models/passport.rb +22 -0
  920. data/spec/support/models/patient.rb +11 -0
  921. data/spec/support/models/pdf_writer.rb +5 -0
  922. data/spec/support/models/pencil.rb +3 -0
  923. data/spec/support/models/person.rb +231 -0
  924. data/spec/support/models/pet.rb +25 -0
  925. data/spec/support/models/pet_owner.rb +8 -0
  926. data/spec/support/models/phone.rb +13 -0
  927. data/spec/support/models/piano.rb +4 -0
  928. data/spec/support/models/pizza.rb +9 -0
  929. data/spec/support/models/player.rb +39 -0
  930. data/spec/support/models/post.rb +52 -0
  931. data/spec/support/models/post_genre.rb +8 -0
  932. data/spec/support/models/powerup.rb +25 -0
  933. data/spec/support/models/preference.rb +11 -0
  934. data/spec/support/models/princess.rb +12 -0
  935. data/spec/support/models/product.rb +19 -0
  936. data/spec/support/models/profile.rb +17 -0
  937. data/spec/support/models/pronunciation.rb +7 -0
  938. data/spec/support/models/pub.rb +8 -0
  939. data/spec/support/models/publication/encyclopedia.rb +11 -0
  940. data/spec/support/models/publication/review.rb +13 -0
  941. data/spec/support/models/publication.rb +4 -0
  942. data/spec/support/models/purchase.rb +6 -0
  943. data/spec/support/models/purchased_item.rb +10 -0
  944. data/spec/support/models/question.rb +10 -0
  945. data/spec/support/models/quiz.rb +9 -0
  946. data/spec/support/models/rating.rb +10 -0
  947. data/spec/support/models/record.rb +54 -0
  948. data/spec/support/models/registry.rb +7 -0
  949. data/spec/support/models/role.rb +9 -0
  950. data/spec/support/models/root_category.rb +6 -0
  951. data/spec/support/models/sandwich.rb +11 -0
  952. data/spec/support/models/scheduler.rb +9 -0
  953. data/spec/support/models/school.rb +14 -0
  954. data/spec/support/models/scribe.rb +7 -0
  955. data/spec/support/models/sealer.rb +7 -0
  956. data/spec/support/models/seat.rb +24 -0
  957. data/spec/support/models/seo.rb +9 -0
  958. data/spec/support/models/series.rb +7 -0
  959. data/spec/support/models/server.rb +15 -0
  960. data/spec/support/models/service.rb +24 -0
  961. data/spec/support/models/shape.rb +14 -0
  962. data/spec/support/models/shelf.rb +7 -0
  963. data/spec/support/models/shield.rb +18 -0
  964. data/spec/support/models/shipment_address.rb +5 -0
  965. data/spec/support/models/shipping_container.rb +7 -0
  966. data/spec/support/models/shipping_pack.rb +5 -0
  967. data/spec/support/models/shirt.rb +11 -0
  968. data/spec/support/models/shop.rb +8 -0
  969. data/spec/support/models/short_agent.rb +6 -0
  970. data/spec/support/models/short_quiz.rb +7 -0
  971. data/spec/support/models/simple.rb +7 -0
  972. data/spec/support/models/slave.rb +8 -0
  973. data/spec/support/models/song.rb +10 -0
  974. data/spec/support/models/sound.rb +7 -0
  975. data/spec/support/models/spacer.rb +7 -0
  976. data/spec/support/models/square.rb +6 -0
  977. data/spec/support/models/staff.rb +9 -0
  978. data/spec/support/models/store_as_dup_test1.rb +7 -0
  979. data/spec/support/models/store_as_dup_test2.rb +7 -0
  980. data/spec/support/models/store_as_dup_test3.rb +7 -0
  981. data/spec/support/models/store_as_dup_test4.rb +7 -0
  982. data/spec/support/models/strategy.rb +5 -0
  983. data/spec/support/models/student.rb +14 -0
  984. data/spec/support/models/sub_item.rb +5 -0
  985. data/spec/support/models/subscription.rb +7 -0
  986. data/spec/support/models/survey.rb +7 -0
  987. data/spec/support/models/symptom.rb +8 -0
  988. data/spec/support/models/system_role.rb +7 -0
  989. data/spec/support/models/tag.rb +10 -0
  990. data/spec/support/models/target.rb +7 -0
  991. data/spec/support/models/template.rb +7 -0
  992. data/spec/support/models/thing.rb +11 -0
  993. data/spec/support/models/threadlocker.rb +7 -0
  994. data/spec/support/models/title.rb +5 -0
  995. data/spec/support/models/tool.rb +10 -0
  996. data/spec/support/models/topping.rb +7 -0
  997. data/spec/support/models/toy.rb +9 -0
  998. data/spec/support/models/track.rb +40 -0
  999. data/spec/support/models/translation.rb +7 -0
  1000. data/spec/support/models/tree.rb +11 -0
  1001. data/spec/support/models/truck.rb +7 -0
  1002. data/spec/support/models/updatable.rb +7 -0
  1003. data/spec/support/models/user.rb +23 -0
  1004. data/spec/support/models/user_account.rb +12 -0
  1005. data/spec/support/models/validation_callback.rb +12 -0
  1006. data/spec/support/models/vehicle.rb +18 -0
  1007. data/spec/support/models/version.rb +7 -0
  1008. data/spec/support/models/vertex.rb +8 -0
  1009. data/spec/support/models/vet_visit.rb +7 -0
  1010. data/spec/support/models/video.rb +15 -0
  1011. data/spec/support/models/video_game.rb +3 -0
  1012. data/spec/support/models/washer.rb +7 -0
  1013. data/spec/support/models/weapon.rb +25 -0
  1014. data/spec/support/models/wiki_page.rb +17 -0
  1015. data/spec/support/models/word.rb +17 -0
  1016. data/spec/support/models/word_origin.rb +13 -0
  1017. data/spec/support/models/writer.rb +13 -0
  1018. data/spec/support/schema_maps/schema_map_aws.json +17 -0
  1019. data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  1020. data/spec/support/schema_maps/schema_map_azure.json +17 -0
  1021. data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
  1022. data/spec/support/schema_maps/schema_map_gcp.json +17 -0
  1023. data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
  1024. data/spec/support/schema_maps/schema_map_kmip.json +17 -0
  1025. data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
  1026. data/spec/support/schema_maps/schema_map_local.json +18 -0
  1027. data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
  1028. data/spec/support/shared/time.rb +53 -0
  1029. data/spec/support/spec_config.rb +64 -0
  1030. data.tar.gz.sig +0 -0
  1031. metadata +1582 -912
  1032. metadata.gz.sig +0 -0
  1033. data/lib/mongoid/atomic/positionable.rb +0 -73
  1034. data/lib/mongoid/callbacks.rb +0 -314
  1035. data/lib/mongoid/components.rb +0 -93
  1036. data/lib/mongoid/config/inflections.rb +0 -6
  1037. data/lib/mongoid/config/validators/session.rb +0 -140
  1038. data/lib/mongoid/contextual/eager.rb +0 -158
  1039. data/lib/mongoid/contextual/find_and_modify.rb +0 -69
  1040. data/lib/mongoid/criterion/findable.rb +0 -179
  1041. data/lib/mongoid/criterion/inspection.rb +0 -25
  1042. data/lib/mongoid/criterion/marshalable.rb +0 -48
  1043. data/lib/mongoid/criterion/modifiable.rb +0 -189
  1044. data/lib/mongoid/criterion/scoping.rb +0 -158
  1045. data/lib/mongoid/dirty.rb +0 -376
  1046. data/lib/mongoid/errors/eager_load.rb +0 -22
  1047. data/lib/mongoid/errors/mixed_session_configuration.rb +0 -28
  1048. data/lib/mongoid/errors/no_default_session.rb +0 -23
  1049. data/lib/mongoid/errors/no_session_config.rb +0 -22
  1050. data/lib/mongoid/errors/no_session_database.rb +0 -27
  1051. data/lib/mongoid/errors/no_session_hosts.rb +0 -27
  1052. data/lib/mongoid/errors/no_sessions_config.rb +0 -20
  1053. data/lib/mongoid/errors/versioning_not_on_root.rb +0 -23
  1054. data/lib/mongoid/finders.rb +0 -130
  1055. data/lib/mongoid/hierarchy.rb +0 -188
  1056. data/lib/mongoid/identity_map.rb +0 -163
  1057. data/lib/mongoid/indexes/validators/options.rb +0 -102
  1058. data/lib/mongoid/indexes.rb +0 -154
  1059. data/lib/mongoid/inspection.rb +0 -55
  1060. data/lib/mongoid/json.rb +0 -16
  1061. data/lib/mongoid/matchers/all.rb +0 -27
  1062. data/lib/mongoid/matchers/and.rb +0 -30
  1063. data/lib/mongoid/matchers/default.rb +0 -72
  1064. data/lib/mongoid/matchers/exists.rb +0 -23
  1065. data/lib/mongoid/matchers/gt.rb +0 -21
  1066. data/lib/mongoid/matchers/gte.rb +0 -21
  1067. data/lib/mongoid/matchers/in.rb +0 -24
  1068. data/lib/mongoid/matchers/lt.rb +0 -21
  1069. data/lib/mongoid/matchers/lte.rb +0 -21
  1070. data/lib/mongoid/matchers/ne.rb +0 -21
  1071. data/lib/mongoid/matchers/nin.rb +0 -21
  1072. data/lib/mongoid/matchers/or.rb +0 -33
  1073. data/lib/mongoid/matchers/size.rb +0 -21
  1074. data/lib/mongoid/matchers/strategies.rb +0 -97
  1075. data/lib/mongoid/matchers.rb +0 -32
  1076. data/lib/mongoid/multi_parameter_attributes.rb +0 -105
  1077. data/lib/mongoid/nested_attributes.rb +0 -78
  1078. data/lib/mongoid/observer.rb +0 -192
  1079. data/lib/mongoid/paranoia.rb +0 -137
  1080. data/lib/mongoid/persistence/atomic/add_to_set.rb +0 -47
  1081. data/lib/mongoid/persistence/atomic/bit.rb +0 -35
  1082. data/lib/mongoid/persistence/atomic/inc.rb +0 -45
  1083. data/lib/mongoid/persistence/atomic/operation.rb +0 -154
  1084. data/lib/mongoid/persistence/atomic/pop.rb +0 -32
  1085. data/lib/mongoid/persistence/atomic/pull.rb +0 -32
  1086. data/lib/mongoid/persistence/atomic/pull_all.rb +0 -32
  1087. data/lib/mongoid/persistence/atomic/push.rb +0 -25
  1088. data/lib/mongoid/persistence/atomic/push_all.rb +0 -25
  1089. data/lib/mongoid/persistence/atomic/rename.rb +0 -30
  1090. data/lib/mongoid/persistence/atomic/sets.rb +0 -28
  1091. data/lib/mongoid/persistence/atomic/unset.rb +0 -27
  1092. data/lib/mongoid/persistence/atomic.rb +0 -231
  1093. data/lib/mongoid/persistence/deletion.rb +0 -32
  1094. data/lib/mongoid/persistence/insertion.rb +0 -38
  1095. data/lib/mongoid/persistence/modification.rb +0 -35
  1096. data/lib/mongoid/persistence/operations/embedded/insert.rb +0 -46
  1097. data/lib/mongoid/persistence/operations/embedded/remove.rb +0 -43
  1098. data/lib/mongoid/persistence/operations/insert.rb +0 -34
  1099. data/lib/mongoid/persistence/operations/remove.rb +0 -33
  1100. data/lib/mongoid/persistence/operations/update.rb +0 -59
  1101. data/lib/mongoid/persistence/operations/upsert.rb +0 -28
  1102. data/lib/mongoid/persistence/operations.rb +0 -214
  1103. data/lib/mongoid/persistence/upsertion.rb +0 -31
  1104. data/lib/mongoid/persistence.rb +0 -352
  1105. data/lib/mongoid/railties/document.rb +0 -12
  1106. data/lib/mongoid/relations/accessors.rb +0 -299
  1107. data/lib/mongoid/relations/auto_save.rb +0 -107
  1108. data/lib/mongoid/relations/binding.rb +0 -241
  1109. data/lib/mongoid/relations/bindings/embedded/in.rb +0 -63
  1110. data/lib/mongoid/relations/bindings/embedded/many.rb +0 -52
  1111. data/lib/mongoid/relations/bindings/embedded/one.rb +0 -55
  1112. data/lib/mongoid/relations/bindings/referenced/in.rb +0 -70
  1113. data/lib/mongoid/relations/bindings/referenced/many.rb +0 -42
  1114. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +0 -67
  1115. data/lib/mongoid/relations/bindings/referenced/one.rb +0 -44
  1116. data/lib/mongoid/relations/bindings.rb +0 -9
  1117. data/lib/mongoid/relations/builder.rb +0 -57
  1118. data/lib/mongoid/relations/builders/embedded/in.rb +0 -29
  1119. data/lib/mongoid/relations/builders/embedded/many.rb +0 -36
  1120. data/lib/mongoid/relations/builders/embedded/one.rb +0 -30
  1121. data/lib/mongoid/relations/builders/nested_attributes/many.rb +0 -177
  1122. data/lib/mongoid/relations/builders/nested_attributes/one.rb +0 -127
  1123. data/lib/mongoid/relations/builders/referenced/in.rb +0 -26
  1124. data/lib/mongoid/relations/builders/referenced/many.rb +0 -27
  1125. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +0 -40
  1126. data/lib/mongoid/relations/builders/referenced/one.rb +0 -26
  1127. data/lib/mongoid/relations/builders.rb +0 -104
  1128. data/lib/mongoid/relations/cascading/delete.rb +0 -44
  1129. data/lib/mongoid/relations/cascading/destroy.rb +0 -43
  1130. data/lib/mongoid/relations/cascading/nullify.rb +0 -35
  1131. data/lib/mongoid/relations/cascading/restrict.rb +0 -39
  1132. data/lib/mongoid/relations/cascading.rb +0 -58
  1133. data/lib/mongoid/relations/constraint.rb +0 -49
  1134. data/lib/mongoid/relations/conversions.rb +0 -34
  1135. data/lib/mongoid/relations/counter_cache.rb +0 -107
  1136. data/lib/mongoid/relations/cyclic.rb +0 -107
  1137. data/lib/mongoid/relations/embedded/batchable.rb +0 -356
  1138. data/lib/mongoid/relations/embedded/in.rb +0 -231
  1139. data/lib/mongoid/relations/embedded/many.rb +0 -659
  1140. data/lib/mongoid/relations/embedded/one.rb +0 -223
  1141. data/lib/mongoid/relations/macros.rb +0 -359
  1142. data/lib/mongoid/relations/many.rb +0 -217
  1143. data/lib/mongoid/relations/marshalable.rb +0 -32
  1144. data/lib/mongoid/relations/metadata.rb +0 -1227
  1145. data/lib/mongoid/relations/nested_builder.rb +0 -74
  1146. data/lib/mongoid/relations/one.rb +0 -60
  1147. data/lib/mongoid/relations/options.rb +0 -48
  1148. data/lib/mongoid/relations/polymorphic.rb +0 -40
  1149. data/lib/mongoid/relations/proxy.rb +0 -264
  1150. data/lib/mongoid/relations/referenced/in.rb +0 -314
  1151. data/lib/mongoid/relations/referenced/many.rb +0 -789
  1152. data/lib/mongoid/relations/referenced/many_to_many.rb +0 -495
  1153. data/lib/mongoid/relations/referenced/one.rb +0 -297
  1154. data/lib/mongoid/relations/reflections.rb +0 -62
  1155. data/lib/mongoid/relations/synchronization.rb +0 -169
  1156. data/lib/mongoid/relations/targets/enumerable.rb +0 -473
  1157. data/lib/mongoid/relations/targets.rb +0 -2
  1158. data/lib/mongoid/relations/touchable.rb +0 -61
  1159. data/lib/mongoid/relations.rb +0 -162
  1160. data/lib/mongoid/reloading.rb +0 -92
  1161. data/lib/mongoid/scoping.rb +0 -356
  1162. data/lib/mongoid/serialization.rb +0 -161
  1163. data/lib/mongoid/sessions/factory.rb +0 -129
  1164. data/lib/mongoid/sessions/mongo_uri.rb +0 -93
  1165. data/lib/mongoid/sessions/validators/storage.rb +0 -49
  1166. data/lib/mongoid/sessions/validators.rb +0 -2
  1167. data/lib/mongoid/sessions.rb +0 -433
  1168. data/lib/mongoid/sharding.rb +0 -61
  1169. data/lib/mongoid/state.rb +0 -97
  1170. data/lib/mongoid/unit_of_work.rb +0 -61
  1171. data/lib/mongoid/validations/associated.rb +0 -46
  1172. data/lib/mongoid/validations/format.rb +0 -20
  1173. data/lib/mongoid/validations/length.rb +0 -20
  1174. data/lib/mongoid/validations/localizable.rb +0 -30
  1175. data/lib/mongoid/validations/macros.rb +0 -93
  1176. data/lib/mongoid/validations/presence.rb +0 -86
  1177. data/lib/mongoid/validations/queryable.rb +0 -31
  1178. data/lib/mongoid/validations/uniqueness.rb +0 -330
  1179. data/lib/mongoid/validations.rb +0 -166
  1180. data/lib/mongoid/versioning.rb +0 -217
  1181. data/lib/rack/mongoid/middleware/identity_map.rb +0 -39
  1182. data/lib/rack/mongoid.rb +0 -2
  1183. data/lib/rails/generators/mongoid/observer/observer_generator.rb +0 -17
  1184. data/lib/rails/generators/mongoid/observer/templates/observer.rb.tt +0 -4
  1185. data/lib/support/ruby_version.rb +0 -26
  1186. data/spec/app/models/account.rb +0 -32
  1187. data/spec/app/models/acolyte.rb +0 -16
  1188. data/spec/app/models/actor.rb +0 -19
  1189. data/spec/app/models/actor_observer.rb +0 -15
  1190. data/spec/app/models/actress.rb +0 -2
  1191. data/spec/app/models/address.rb +0 -72
  1192. data/spec/app/models/address_component.rb +0 -5
  1193. data/spec/app/models/address_number.rb +0 -6
  1194. data/spec/app/models/agency.rb +0 -5
  1195. data/spec/app/models/agent.rb +0 -12
  1196. data/spec/app/models/album.rb +0 -14
  1197. data/spec/app/models/alert.rb +0 -5
  1198. data/spec/app/models/animal.rb +0 -25
  1199. data/spec/app/models/answer.rb +0 -4
  1200. data/spec/app/models/appointment.rb +0 -7
  1201. data/spec/app/models/article.rb +0 -13
  1202. data/spec/app/models/artist.rb +0 -66
  1203. data/spec/app/models/artwork.rb +0 -4
  1204. data/spec/app/models/augmentation.rb +0 -11
  1205. data/spec/app/models/author.rb +0 -6
  1206. data/spec/app/models/band.rb +0 -25
  1207. data/spec/app/models/bar.rb +0 -9
  1208. data/spec/app/models/basic.rb +0 -6
  1209. data/spec/app/models/bed.rb +0 -1
  1210. data/spec/app/models/big_palette.rb +0 -2
  1211. data/spec/app/models/birthday.rb +0 -13
  1212. data/spec/app/models/book.rb +0 -12
  1213. data/spec/app/models/breed.rb +0 -4
  1214. data/spec/app/models/browser.rb +0 -6
  1215. data/spec/app/models/building.rb +0 -7
  1216. data/spec/app/models/building_address.rb +0 -7
  1217. data/spec/app/models/bus.rb +0 -7
  1218. data/spec/app/models/business.rb +0 -5
  1219. data/spec/app/models/callback_recorder.rb +0 -25
  1220. data/spec/app/models/callback_test.rb +0 -9
  1221. data/spec/app/models/canvas.rb +0 -25
  1222. data/spec/app/models/car.rb +0 -1
  1223. data/spec/app/models/cat.rb +0 -8
  1224. data/spec/app/models/category.rb +0 -8
  1225. data/spec/app/models/child.rb +0 -4
  1226. data/spec/app/models/child_doc.rb +0 -22
  1227. data/spec/app/models/church.rb +0 -4
  1228. data/spec/app/models/circle.rb +0 -3
  1229. data/spec/app/models/circuit.rb +0 -4
  1230. data/spec/app/models/circus.rb +0 -7
  1231. data/spec/app/models/code.rb +0 -5
  1232. data/spec/app/models/comment.rb +0 -16
  1233. data/spec/app/models/contractor.rb +0 -7
  1234. data/spec/app/models/cookie.rb +0 -6
  1235. data/spec/app/models/country_code.rb +0 -8
  1236. data/spec/app/models/definition.rb +0 -8
  1237. data/spec/app/models/description.rb +0 -11
  1238. data/spec/app/models/dictionary.rb +0 -10
  1239. data/spec/app/models/division.rb +0 -10
  1240. data/spec/app/models/doctor.rb +0 -12
  1241. data/spec/app/models/dog.rb +0 -7
  1242. data/spec/app/models/dokument.rb +0 -5
  1243. data/spec/app/models/driver.rb +0 -7
  1244. data/spec/app/models/drug.rb +0 -8
  1245. data/spec/app/models/email.rb +0 -6
  1246. data/spec/app/models/employer.rb +0 -5
  1247. data/spec/app/models/entry.rb +0 -6
  1248. data/spec/app/models/eraser.rb +0 -1
  1249. data/spec/app/models/event.rb +0 -22
  1250. data/spec/app/models/exhibition.rb +0 -4
  1251. data/spec/app/models/exhibitor.rb +0 -5
  1252. data/spec/app/models/eye.rb +0 -9
  1253. data/spec/app/models/eye_bowl.rb +0 -9
  1254. data/spec/app/models/face.rb +0 -8
  1255. data/spec/app/models/favorite.rb +0 -6
  1256. data/spec/app/models/filesystem.rb +0 -4
  1257. data/spec/app/models/fire_hydrant.rb +0 -6
  1258. data/spec/app/models/firefox.rb +0 -4
  1259. data/spec/app/models/fish.rb +0 -8
  1260. data/spec/app/models/folder.rb +0 -7
  1261. data/spec/app/models/folder_item.rb +0 -9
  1262. data/spec/app/models/fruits.rb +0 -28
  1263. data/spec/app/models/game.rb +0 -21
  1264. data/spec/app/models/ghost.rb +0 -7
  1265. data/spec/app/models/home.rb +0 -4
  1266. data/spec/app/models/house.rb +0 -8
  1267. data/spec/app/models/html_writer.rb +0 -3
  1268. data/spec/app/models/image.rb +0 -22
  1269. data/spec/app/models/implant.rb +0 -16
  1270. data/spec/app/models/item.rb +0 -12
  1271. data/spec/app/models/jar.rb +0 -7
  1272. data/spec/app/models/label.rb +0 -40
  1273. data/spec/app/models/language.rb +0 -5
  1274. data/spec/app/models/lat_lng.rb +0 -15
  1275. data/spec/app/models/league.rb +0 -11
  1276. data/spec/app/models/learner.rb +0 -2
  1277. data/spec/app/models/line_item.rb +0 -6
  1278. data/spec/app/models/location.rb +0 -8
  1279. data/spec/app/models/login.rb +0 -8
  1280. data/spec/app/models/manufacturer.rb +0 -7
  1281. data/spec/app/models/meat.rb +0 -4
  1282. data/spec/app/models/membership.rb +0 -4
  1283. data/spec/app/models/mixed_drink.rb +0 -4
  1284. data/spec/app/models/movie.rb +0 -12
  1285. data/spec/app/models/my_hash.rb +0 -2
  1286. data/spec/app/models/name.rb +0 -23
  1287. data/spec/app/models/node.rb +0 -5
  1288. data/spec/app/models/note.rb +0 -12
  1289. data/spec/app/models/ordered_post.rb +0 -6
  1290. data/spec/app/models/ordered_preference.rb +0 -6
  1291. data/spec/app/models/oscar.rb +0 -15
  1292. data/spec/app/models/override.rb +0 -16
  1293. data/spec/app/models/ownable.rb +0 -6
  1294. data/spec/app/models/owner.rb +0 -6
  1295. data/spec/app/models/pack.rb +0 -3
  1296. data/spec/app/models/page.rb +0 -5
  1297. data/spec/app/models/page_question.rb +0 -4
  1298. data/spec/app/models/palette.rb +0 -7
  1299. data/spec/app/models/paranoid_phone.rb +0 -25
  1300. data/spec/app/models/paranoid_post.rb +0 -36
  1301. data/spec/app/models/parent.rb +0 -5
  1302. data/spec/app/models/parent_doc.rb +0 -6
  1303. data/spec/app/models/passport.rb +0 -5
  1304. data/spec/app/models/patient.rb +0 -9
  1305. data/spec/app/models/pdf_writer.rb +0 -3
  1306. data/spec/app/models/pencil.rb +0 -1
  1307. data/spec/app/models/person.rb +0 -201
  1308. data/spec/app/models/pet.rb +0 -23
  1309. data/spec/app/models/pet_owner.rb +0 -6
  1310. data/spec/app/models/phone.rb +0 -11
  1311. data/spec/app/models/phone_observer.rb +0 -6
  1312. data/spec/app/models/pizza.rb +0 -7
  1313. data/spec/app/models/player.rb +0 -35
  1314. data/spec/app/models/post.rb +0 -43
  1315. data/spec/app/models/powerup.rb +0 -11
  1316. data/spec/app/models/preference.rb +0 -9
  1317. data/spec/app/models/princess.rb +0 -8
  1318. data/spec/app/models/product.rb +0 -17
  1319. data/spec/app/models/profile.rb +0 -5
  1320. data/spec/app/models/pronunciation.rb +0 -5
  1321. data/spec/app/models/purchase.rb +0 -4
  1322. data/spec/app/models/question.rb +0 -8
  1323. data/spec/app/models/quiz.rb +0 -10
  1324. data/spec/app/models/rating.rb +0 -8
  1325. data/spec/app/models/record.rb +0 -46
  1326. data/spec/app/models/registry.rb +0 -4
  1327. data/spec/app/models/role.rb +0 -7
  1328. data/spec/app/models/root_category.rb +0 -4
  1329. data/spec/app/models/sandwich.rb +0 -4
  1330. data/spec/app/models/scheduler.rb +0 -7
  1331. data/spec/app/models/seo.rb +0 -7
  1332. data/spec/app/models/series.rb +0 -4
  1333. data/spec/app/models/server.rb +0 -13
  1334. data/spec/app/models/service.rb +0 -22
  1335. data/spec/app/models/shape.rb +0 -12
  1336. data/spec/app/models/shelf.rb +0 -5
  1337. data/spec/app/models/shipping_container.rb +0 -5
  1338. data/spec/app/models/shipping_pack.rb +0 -3
  1339. data/spec/app/models/shop.rb +0 -6
  1340. data/spec/app/models/short_agent.rb +0 -4
  1341. data/spec/app/models/short_quiz.rb +0 -5
  1342. data/spec/app/models/slave.rb +0 -6
  1343. data/spec/app/models/song.rb +0 -8
  1344. data/spec/app/models/square.rb +0 -4
  1345. data/spec/app/models/strategy.rb +0 -3
  1346. data/spec/app/models/sub_item.rb +0 -3
  1347. data/spec/app/models/subscription.rb +0 -4
  1348. data/spec/app/models/survey.rb +0 -5
  1349. data/spec/app/models/symptom.rb +0 -6
  1350. data/spec/app/models/tag.rb +0 -8
  1351. data/spec/app/models/target.rb +0 -5
  1352. data/spec/app/models/template.rb +0 -5
  1353. data/spec/app/models/thing.rb +0 -9
  1354. data/spec/app/models/title.rb +0 -4
  1355. data/spec/app/models/tool.rb +0 -8
  1356. data/spec/app/models/topping.rb +0 -5
  1357. data/spec/app/models/track.rb +0 -38
  1358. data/spec/app/models/translation.rb +0 -5
  1359. data/spec/app/models/tree.rb +0 -9
  1360. data/spec/app/models/truck.rb +0 -3
  1361. data/spec/app/models/user.rb +0 -21
  1362. data/spec/app/models/user_account.rb +0 -10
  1363. data/spec/app/models/validation_callback.rb +0 -10
  1364. data/spec/app/models/vehicle.rb +0 -11
  1365. data/spec/app/models/version.rb +0 -5
  1366. data/spec/app/models/vet_visit.rb +0 -5
  1367. data/spec/app/models/video.rb +0 -17
  1368. data/spec/app/models/video_game.rb +0 -1
  1369. data/spec/app/models/weapon.rb +0 -11
  1370. data/spec/app/models/wiki_page.rb +0 -17
  1371. data/spec/app/models/word.rb +0 -12
  1372. data/spec/app/models/word_origin.rb +0 -11
  1373. data/spec/app/models/writer.rb +0 -11
  1374. data/spec/mongoid/atomic/positionable_spec.rb +0 -227
  1375. data/spec/mongoid/attributes/processing_spec.rb +0 -149
  1376. data/spec/mongoid/callbacks_spec.rb +0 -1564
  1377. data/spec/mongoid/components_spec.rb +0 -24
  1378. data/spec/mongoid/contextual/find_and_modify_spec.rb +0 -220
  1379. data/spec/mongoid/criterion/destructive_spec.rb +0 -101
  1380. data/spec/mongoid/criterion/inspection_spec.rb +0 -27
  1381. data/spec/mongoid/criterion/marshalable_spec.rb +0 -28
  1382. data/spec/mongoid/criterion/modifiable_spec.rb +0 -409
  1383. data/spec/mongoid/criterion/modification_spec.rb +0 -402
  1384. data/spec/mongoid/criterion/scoping_spec.rb +0 -391
  1385. data/spec/mongoid/dirty_spec.rb +0 -1508
  1386. data/spec/mongoid/errors/eager_load_spec.rb +0 -29
  1387. data/spec/mongoid/errors/mixed_session_configuration_spec.rb +0 -29
  1388. data/spec/mongoid/errors/no_session_config_spec.rb +0 -29
  1389. data/spec/mongoid/errors/no_session_database_spec.rb +0 -29
  1390. data/spec/mongoid/errors/no_session_hosts_spec.rb +0 -29
  1391. data/spec/mongoid/errors/no_sessions_config_spec.rb +0 -29
  1392. data/spec/mongoid/errors/versioning_not_on_root_spec.rb +0 -29
  1393. data/spec/mongoid/fields/internal/foreign_keys/array_spec.rb +0 -184
  1394. data/spec/mongoid/fields/internal/foreign_keys/object_spec.rb +0 -201
  1395. data/spec/mongoid/finders_spec.rb +0 -321
  1396. data/spec/mongoid/hierarchy_spec.rb +0 -244
  1397. data/spec/mongoid/identity_map_spec.rb +0 -564
  1398. data/spec/mongoid/indexes_spec.rb +0 -404
  1399. data/spec/mongoid/inspection_spec.rb +0 -57
  1400. data/spec/mongoid/json_spec.rb +0 -33
  1401. data/spec/mongoid/matchers/all_spec.rb +0 -31
  1402. data/spec/mongoid/matchers/and_spec.rb +0 -162
  1403. data/spec/mongoid/matchers/default_spec.rb +0 -130
  1404. data/spec/mongoid/matchers/exists_spec.rb +0 -57
  1405. data/spec/mongoid/matchers/gt_spec.rb +0 -74
  1406. data/spec/mongoid/matchers/gte_spec.rb +0 -74
  1407. data/spec/mongoid/matchers/in_spec.rb +0 -25
  1408. data/spec/mongoid/matchers/lt_spec.rb +0 -74
  1409. data/spec/mongoid/matchers/lte_spec.rb +0 -74
  1410. data/spec/mongoid/matchers/ne_spec.rb +0 -25
  1411. data/spec/mongoid/matchers/nin_spec.rb +0 -25
  1412. data/spec/mongoid/matchers/or_spec.rb +0 -106
  1413. data/spec/mongoid/matchers/size_spec.rb +0 -25
  1414. data/spec/mongoid/matchers_spec.rb +0 -532
  1415. data/spec/mongoid/multi_parameter_attributes_spec.rb +0 -128
  1416. data/spec/mongoid/nested_attributes_spec.rb +0 -4945
  1417. data/spec/mongoid/observer_spec.rb +0 -290
  1418. data/spec/mongoid/paranoia_spec.rb +0 -759
  1419. data/spec/mongoid/persistence/atomic/add_to_set_spec.rb +0 -262
  1420. data/spec/mongoid/persistence/atomic/bit_spec.rb +0 -88
  1421. data/spec/mongoid/persistence/atomic/inc_spec.rb +0 -133
  1422. data/spec/mongoid/persistence/atomic/pop_spec.rb +0 -111
  1423. data/spec/mongoid/persistence/atomic/pull_all_spec.rb +0 -77
  1424. data/spec/mongoid/persistence/atomic/pull_spec.rb +0 -80
  1425. data/spec/mongoid/persistence/atomic/push_all_spec.rb +0 -77
  1426. data/spec/mongoid/persistence/atomic/push_spec.rb +0 -77
  1427. data/spec/mongoid/persistence/atomic/rename_spec.rb +0 -42
  1428. data/spec/mongoid/persistence/atomic/sets_spec.rb +0 -154
  1429. data/spec/mongoid/persistence/atomic/unset_spec.rb +0 -65
  1430. data/spec/mongoid/persistence/atomic_spec.rb +0 -216
  1431. data/spec/mongoid/persistence/operations/embedded/insert_spec.rb +0 -191
  1432. data/spec/mongoid/persistence/operations/embedded/remove_spec.rb +0 -8
  1433. data/spec/mongoid/persistence/operations/insert_spec.rb +0 -149
  1434. data/spec/mongoid/persistence/operations/remove_spec.rb +0 -113
  1435. data/spec/mongoid/persistence/operations/update_spec.rb +0 -141
  1436. data/spec/mongoid/persistence/operations/upsert_spec.rb +0 -59
  1437. data/spec/mongoid/persistence/operations_spec.rb +0 -313
  1438. data/spec/mongoid/persistence_spec.rb +0 -2279
  1439. data/spec/mongoid/railties/document_spec.rb +0 -24
  1440. data/spec/mongoid/relations/accessors_spec.rb +0 -844
  1441. data/spec/mongoid/relations/auto_save_spec.rb +0 -261
  1442. data/spec/mongoid/relations/bindings/embedded/in_spec.rb +0 -171
  1443. data/spec/mongoid/relations/bindings/embedded/many_spec.rb +0 -54
  1444. data/spec/mongoid/relations/bindings/embedded/one_spec.rb +0 -77
  1445. data/spec/mongoid/relations/bindings/referenced/in_spec.rb +0 -241
  1446. data/spec/mongoid/relations/bindings/referenced/many_spec.rb +0 -153
  1447. data/spec/mongoid/relations/bindings/referenced/many_to_many_spec.rb +0 -178
  1448. data/spec/mongoid/relations/bindings/referenced/one_spec.rb +0 -131
  1449. data/spec/mongoid/relations/builders/embedded/in_spec.rb +0 -34
  1450. data/spec/mongoid/relations/builders/embedded/many_spec.rb +0 -132
  1451. data/spec/mongoid/relations/builders/embedded/one_spec.rb +0 -99
  1452. data/spec/mongoid/relations/builders/nested_attributes/many_spec.rb +0 -234
  1453. data/spec/mongoid/relations/builders/nested_attributes/one_spec.rb +0 -250
  1454. data/spec/mongoid/relations/builders/referenced/in_spec.rb +0 -241
  1455. data/spec/mongoid/relations/builders/referenced/many_spec.rb +0 -137
  1456. data/spec/mongoid/relations/builders/referenced/many_to_many_spec.rb +0 -178
  1457. data/spec/mongoid/relations/builders/referenced/one_spec.rb +0 -124
  1458. data/spec/mongoid/relations/builders_spec.rb +0 -226
  1459. data/spec/mongoid/relations/cascading/delete_spec.rb +0 -101
  1460. data/spec/mongoid/relations/cascading/destroy_spec.rb +0 -47
  1461. data/spec/mongoid/relations/cascading/nullify_spec.rb +0 -32
  1462. data/spec/mongoid/relations/cascading/restrict_spec.rb +0 -68
  1463. data/spec/mongoid/relations/cascading_spec.rb +0 -355
  1464. data/spec/mongoid/relations/constraint_spec.rb +0 -74
  1465. data/spec/mongoid/relations/conversions_spec.rb +0 -126
  1466. data/spec/mongoid/relations/counter_cache_spec.rb +0 -205
  1467. data/spec/mongoid/relations/cyclic_spec.rb +0 -156
  1468. data/spec/mongoid/relations/embedded/dirty_spec.rb +0 -65
  1469. data/spec/mongoid/relations/embedded/in_spec.rb +0 -580
  1470. data/spec/mongoid/relations/embedded/many_spec.rb +0 -3841
  1471. data/spec/mongoid/relations/embedded/one_spec.rb +0 -1055
  1472. data/spec/mongoid/relations/macros_spec.rb +0 -625
  1473. data/spec/mongoid/relations/metadata_spec.rb +0 -2030
  1474. data/spec/mongoid/relations/options_spec.rb +0 -35
  1475. data/spec/mongoid/relations/polymorphic_spec.rb +0 -132
  1476. data/spec/mongoid/relations/referenced/in_spec.rb +0 -1501
  1477. data/spec/mongoid/relations/referenced/many_spec.rb +0 -3632
  1478. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +0 -3561
  1479. data/spec/mongoid/relations/referenced/one_spec.rb +0 -1331
  1480. data/spec/mongoid/relations/reflections_spec.rb +0 -101
  1481. data/spec/mongoid/relations/synchronization_spec.rb +0 -453
  1482. data/spec/mongoid/relations/targets/enumerable_spec.rb +0 -1710
  1483. data/spec/mongoid/relations_spec.rb +0 -188
  1484. data/spec/mongoid/reloading_spec.rb +0 -305
  1485. data/spec/mongoid/scoping_spec.rb +0 -978
  1486. data/spec/mongoid/serialization_spec.rb +0 -833
  1487. data/spec/mongoid/sessions/factory_spec.rb +0 -312
  1488. data/spec/mongoid/sessions/mongo_uri_spec.rb +0 -103
  1489. data/spec/mongoid/sessions_spec.rb +0 -1111
  1490. data/spec/mongoid/sharding_spec.rb +0 -61
  1491. data/spec/mongoid/state_spec.rb +0 -102
  1492. data/spec/mongoid/unit_of_work_spec.rb +0 -196
  1493. data/spec/mongoid/validations/associated_spec.rb +0 -183
  1494. data/spec/mongoid/validations/format_spec.rb +0 -83
  1495. data/spec/mongoid/validations/length_spec.rb +0 -223
  1496. data/spec/mongoid/validations/numericality_spec.rb +0 -30
  1497. data/spec/mongoid/validations/presence_spec.rb +0 -592
  1498. data/spec/mongoid/validations/uniqueness_spec.rb +0 -2399
  1499. data/spec/mongoid/validations_spec.rb +0 -309
  1500. data/spec/mongoid/versioning_spec.rb +0 -540
  1501. data/spec/rack/mongoid/middleware/identity_map_spec.rb +0 -72
@@ -0,0 +1,5000 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require_relative '../association/referenced/has_many_models'
5
+ require_relative '../association/referenced/has_and_belongs_to_many_models'
6
+ require_relative './nested_spec_models'
7
+
8
+ describe Mongoid::Attributes::Nested do
9
+
10
+ describe ".accepts_nested_attributes_for" do
11
+
12
+ context "when the autosave option is not defined" do
13
+
14
+ let(:person) do
15
+ Person.new
16
+ end
17
+
18
+ before do
19
+ Person.accepts_nested_attributes_for :favorites
20
+ Person.accepts_nested_attributes_for :children
21
+ end
22
+
23
+ after do
24
+ Person.send(:undef_method, :favorites_attributes=)
25
+ Person.send(:undef_method, :children_attributes=)
26
+ Person.nested_attributes.clear
27
+ end
28
+
29
+ it "adds a method for handling the attributes" do
30
+ expect(person).to respond_to(:favorites_attributes=)
31
+ end
32
+
33
+ it "does not autosave if the association is embedded" do
34
+ expect(person).not_to respond_to(:autosave_documents_for_favorites)
35
+ end
36
+
37
+ it "autosaves if the association is not embedded" do
38
+ expect(person).to respond_to(:autosave_documents_for_children)
39
+ end
40
+
41
+ it "adds the method name to the nested attributes list" do
42
+ expect(Person.nested_attributes).to eq({
43
+ "favorites_attributes" => "favorites_attributes=",
44
+ "children_attributes" => "children_attributes="
45
+ })
46
+ end
47
+ end
48
+
49
+ context "when autosave is explicitly false" do
50
+
51
+ before do
52
+ Account.accepts_nested_attributes_for :alerts
53
+ end
54
+
55
+ after do
56
+ Account.send(:undef_method, :alerts_attributes=)
57
+ Account.nested_attributes.clear
58
+ end
59
+
60
+ let(:association) do
61
+ Account.reflect_on_association(:alerts)
62
+ end
63
+
64
+ it "keeps autosave set to false" do
65
+ expect(association).to_not be_autosave
66
+ end
67
+ end
68
+ end
69
+
70
+ describe "#initialize" do
71
+
72
+ context "when the relation is an embeds one" do
73
+
74
+ before do
75
+ Person.send(:undef_method, :name_attributes=)
76
+ Person.accepts_nested_attributes_for :name
77
+ end
78
+
79
+ let(:person) do
80
+ Person.new(name_attributes: { first_name: "Johnny" })
81
+ end
82
+
83
+ it "sets the nested attributes" do
84
+ expect(person.name.first_name).to eq("Johnny")
85
+ end
86
+ end
87
+
88
+ context "when the relation is an embeds many" do
89
+
90
+ before do
91
+ Person.send(:undef_method, :addresses_attributes=)
92
+ Person.accepts_nested_attributes_for :addresses
93
+ end
94
+
95
+ let(:person) do
96
+ Person.new(addresses_attributes: { "1" => { street: "Alexanderstr" }})
97
+ end
98
+
99
+ it "sets the nested attributes" do
100
+ expect(person.addresses.first.street).to eq("Alexanderstr")
101
+ end
102
+
103
+ context "when there are 10 or more child records" do
104
+
105
+ let(:person) do
106
+ Person.new(addresses: addresses)
107
+ end
108
+
109
+ let(:addresses) do
110
+ ('0'..'10').inject({}) do |addresses,i|
111
+ addresses.merge(i => {number: i})
112
+ end
113
+ end
114
+
115
+ it "preserves the order of the children" do
116
+ expect(person.addresses.map(&:number)).to eq((0..10).to_a)
117
+ end
118
+ end
119
+ end
120
+
121
+ context "when the association is referenced in and polymorphic" do
122
+
123
+ it "infers the class name of the polymorphic with the inverse type" do
124
+ expect {
125
+ Post.create!(
126
+ title: "Some title",
127
+ posteable_type: "Sandwich",
128
+ posteable_attributes: { name: 'Grilled Cheese' }
129
+ )
130
+ }.not_to raise_error
131
+ end
132
+ end
133
+
134
+ context "when the relation is an embedded in" do
135
+
136
+ before do
137
+ Video.accepts_nested_attributes_for :person
138
+ end
139
+
140
+ let(:video) do
141
+ Video.new(person_attributes: { title: "Sir" })
142
+ end
143
+
144
+ it "sets the nested attributes" do
145
+ expect(video.person.title).to eq("Sir")
146
+ end
147
+ end
148
+
149
+ context "when the relation is a references one" do
150
+
151
+ before do
152
+ Person.send(:undef_method, :game_attributes=)
153
+ Person.accepts_nested_attributes_for :game
154
+ end
155
+
156
+ let(:person) do
157
+ Person.new(game_attributes: { name: "Tron" })
158
+ end
159
+
160
+ it "sets the nested attributes" do
161
+ expect(person.game.name).to eq("Tron")
162
+ end
163
+ end
164
+
165
+ context "when the relation is a references many" do
166
+
167
+ before do
168
+ Person.send(:undef_method, :posts_attributes=)
169
+ Person.accepts_nested_attributes_for :posts
170
+ end
171
+
172
+ let(:person) do
173
+ Person.new(posts_attributes: { "1" => { title: "First" }})
174
+ end
175
+
176
+ it "sets the nested attributes" do
177
+ expect(person.posts.first.title).to eq("First")
178
+ end
179
+ end
180
+
181
+ context "when the relation is a references and referenced in many" do
182
+
183
+ before do
184
+ Person.send(:undef_method, :preferences_attributes=)
185
+ Person.accepts_nested_attributes_for :preferences
186
+ end
187
+
188
+ let(:person) do
189
+ Person.new(preferences_attributes: { "1" => { name: "First" }})
190
+ end
191
+
192
+ it "sets the nested attributes" do
193
+ expect(person.preferences.first.name).to eq("First")
194
+ end
195
+
196
+ context "when adding existing document to a relation" do
197
+ let(:preference) { Preference.create!(name: 'sample preference') }
198
+ let(:person) do
199
+ Person.new(
200
+ preferences_attributes: { 0 => { id: preference.id, name: preference.name } }
201
+ )
202
+ end
203
+
204
+ it "sets the nested attributes" do
205
+ expect(person.preferences.map(&:name)).to eq([preference.name])
206
+ end
207
+
208
+ it "updates attributes of existing document which is added to relation" do
209
+ preference_name = 'updated preference'
210
+ person = Person.new(
211
+ preferences_attributes: { 0 => { id: preference.id, name: preference_name } }
212
+ )
213
+ expect(person.preferences.map(&:name)).to eq([preference_name])
214
+ end
215
+ end
216
+ end
217
+
218
+ context "when the relation is a referenced in" do
219
+
220
+ before do
221
+ Post.accepts_nested_attributes_for :person, autosave: false
222
+ end
223
+
224
+ after do
225
+ Post.send(:undef_method, :person_attributes=)
226
+ Post.nested_attributes.clear
227
+ end
228
+
229
+ let(:post) do
230
+ Post.new(person_attributes: { title: "Sir" })
231
+ end
232
+
233
+ it "sets the nested attributes" do
234
+ expect(post.person.title).to eq("Sir")
235
+ end
236
+ end
237
+ end
238
+
239
+ describe "*_attributes=" do
240
+
241
+ context "when the parent document is new" do
242
+
243
+ context "when the relation is an embeds one" do
244
+
245
+ context "when the parent document is persisted" do
246
+
247
+ let(:person) do
248
+ Person.create!
249
+ end
250
+
251
+ before do
252
+ Person.send(:undef_method, :name_attributes=)
253
+ Person.accepts_nested_attributes_for :name, allow_destroy: true
254
+ end
255
+
256
+ after do
257
+ Person.send(:undef_method, :name_attributes=)
258
+ Person.accepts_nested_attributes_for :name
259
+ end
260
+
261
+ context "when setting the child attributes" do
262
+
263
+ before do
264
+ person.name_attributes = { last_name: "Fischer" }
265
+ end
266
+
267
+ it "sets the child document" do
268
+ expect(person.name.last_name).to eq("Fischer")
269
+ end
270
+
271
+ it "does not persist the child document" do
272
+ expect(person.name).to_not be_persisted
273
+ end
274
+
275
+ context "when saving the parent" do
276
+
277
+ before do
278
+ person.save!
279
+ person.reload
280
+ end
281
+
282
+ it "persists the child document" do
283
+ expect(person.name).to be_persisted
284
+ end
285
+ end
286
+ end
287
+ end
288
+
289
+ let(:person) do
290
+ Person.new
291
+ end
292
+
293
+ context "when a reject proc is specified" do
294
+
295
+ before do
296
+ Person.send(:undef_method, :name_attributes=)
297
+ Person.accepts_nested_attributes_for \
298
+ :name, reject_if: ->(attrs){ attrs[:first_name].blank? }
299
+ end
300
+
301
+ after do
302
+ Person.send(:undef_method, :name_attributes=)
303
+ Person.accepts_nested_attributes_for :name
304
+ end
305
+
306
+ context "when the attributes match" do
307
+
308
+ before do
309
+ person.name_attributes = { last_name: "Lang" }
310
+ end
311
+
312
+ it "does not add the document" do
313
+ expect(person.name).to be_nil
314
+ end
315
+ end
316
+
317
+ context "when the attributes do not match" do
318
+
319
+ before do
320
+ person.name_attributes = { first_name: "Lang" }
321
+ end
322
+
323
+ it "adds the document" do
324
+ expect(person.name.first_name).to eq("Lang")
325
+ end
326
+ end
327
+ end
328
+
329
+ context "when :reject_if => :all_blank is specified" do
330
+
331
+ context "when the relation is not autobuilding" do
332
+
333
+ before do
334
+ Person.send(:undef_method, :name_attributes=)
335
+ Person.accepts_nested_attributes_for \
336
+ :name, reject_if: :all_blank
337
+ end
338
+
339
+ after do
340
+ Person.send(:undef_method, :name_attributes=)
341
+ Person.accepts_nested_attributes_for :name
342
+ end
343
+
344
+ context "when all attributes are empty" do
345
+
346
+ before do
347
+ person.name_attributes = { last_name: "" }
348
+ end
349
+
350
+ it "does not add the document" do
351
+ expect(person.name).to be_nil
352
+ end
353
+ end
354
+
355
+ context "when an attribute is non-empty" do
356
+
357
+ before do
358
+ person.name_attributes = { first_name: "Lang" }
359
+ end
360
+
361
+ it "adds the document" do
362
+ expect(person.name.first_name).to eq("Lang")
363
+ end
364
+ end
365
+ end
366
+
367
+ context "when the relation is autobuilding" do
368
+
369
+ before do
370
+ Product.accepts_nested_attributes_for :seo, reject_if: :all_blank
371
+ end
372
+
373
+ after do
374
+ Product.send(:undef_method, :seo_attributes=)
375
+ end
376
+
377
+ context "when all attributes are empty" do
378
+
379
+ let(:product) do
380
+ Product.create!(name: "testing")
381
+ end
382
+
383
+ it "does not add the document" do
384
+ expect(product.seo).to_not be_persisted
385
+ end
386
+ end
387
+ end
388
+ end
389
+
390
+ context "when no id has been passed" do
391
+
392
+ context "with no destroy attribute" do
393
+
394
+ before do
395
+ person.name_attributes = { first_name: "Leo" }
396
+ end
397
+
398
+ it "builds a new document" do
399
+ expect(person.name.first_name).to eq("Leo")
400
+ end
401
+ end
402
+
403
+ context "with a destroy attribute" do
404
+
405
+ context "when allow_destroy is true" do
406
+
407
+ before do
408
+ Person.send(:undef_method, :name_attributes=)
409
+ Person.accepts_nested_attributes_for :name, allow_destroy: true
410
+ end
411
+
412
+ after do
413
+ Person.send(:undef_method, :name_attributes=)
414
+ Person.accepts_nested_attributes_for :name
415
+ end
416
+
417
+ context "when destroy is a symbol" do
418
+
419
+ before do
420
+ person.name_attributes = { first_name: "Leo", _destroy: "1" }
421
+ end
422
+
423
+ it "does not build the document" do
424
+ expect(person.name).to be_nil
425
+ end
426
+ end
427
+
428
+ context "when destroy is a string" do
429
+
430
+ before do
431
+ person.name_attributes = { first_name: "Leo", "_destroy" => "1" }
432
+ end
433
+
434
+ it "does not build the document" do
435
+ expect(person.name).to be_nil
436
+ end
437
+ end
438
+ end
439
+
440
+ context "when allow_destroy is false" do
441
+
442
+ before do
443
+ Person.send(:undef_method, :name_attributes=)
444
+ Person.accepts_nested_attributes_for :name, allow_destroy: false
445
+ end
446
+
447
+ after do
448
+ Person.send(:undef_method, :name_attributes=)
449
+ Person.accepts_nested_attributes_for :name
450
+ end
451
+
452
+ before do
453
+ person.name_attributes = { first_name: "Leo", _destroy: "1" }
454
+ end
455
+
456
+ it "builds the document" do
457
+ expect(person.name.first_name).to eq("Leo")
458
+ end
459
+ end
460
+ end
461
+
462
+ context "with empty attributes" do
463
+
464
+ before do
465
+ person.name_attributes = {}
466
+ end
467
+
468
+ it "does not build the document" do
469
+ expect(person.name).to be_nil
470
+ end
471
+ end
472
+
473
+ context "when there is an existing document" do
474
+
475
+ context "with no destroy attribute" do
476
+
477
+ before do
478
+ person.name = Name.new(first_name: "Michael")
479
+ person.name_attributes = { first_name: "Jack" }
480
+ end
481
+
482
+ it "replaces the document" do
483
+ expect(person.name.first_name).to eq("Jack")
484
+ end
485
+ end
486
+
487
+ context "with a destroy attribute" do
488
+
489
+ context "when allow_destroy is true" do
490
+
491
+ before do
492
+ Person.send(:undef_method, :name_attributes=)
493
+ Person.accepts_nested_attributes_for :name, allow_destroy: true
494
+ end
495
+
496
+ after do
497
+ Person.send(:undef_method, :name_attributes=)
498
+ Person.accepts_nested_attributes_for :name
499
+ end
500
+
501
+ before do
502
+ person.name = Name.new(first_name: "Michael")
503
+ person.name_attributes = { first_name: "Jack", _destroy: "1" }
504
+ end
505
+
506
+ it "does not replace the document" do
507
+ expect(person.name.first_name).to eq("Michael")
508
+ end
509
+ end
510
+
511
+ context "when allow_destroy is false" do
512
+
513
+ before do
514
+ Person.send(:undef_method, :name_attributes=)
515
+ Person.accepts_nested_attributes_for :name, allow_destroy: false
516
+ end
517
+
518
+ after do
519
+ Person.send(:undef_method, :name_attributes=)
520
+ Person.accepts_nested_attributes_for :name
521
+ end
522
+
523
+ before do
524
+ person.name = Name.new(first_name: "Michael")
525
+ person.name_attributes = { first_name: "Jack", _destroy: "1" }
526
+ end
527
+
528
+ it "replaces the document" do
529
+ expect(person.name.first_name).to eq("Jack")
530
+ end
531
+ end
532
+ end
533
+ end
534
+ end
535
+
536
+ context "when an id is passed" do
537
+
538
+ context "when there is an existing record" do
539
+
540
+ let(:name) do
541
+ Name.new(first_name: "Joe")
542
+ end
543
+
544
+ before do
545
+ person.name = name
546
+ end
547
+
548
+ context "when the id matches" do
549
+
550
+ context "when passed keys as symbols" do
551
+
552
+ before do
553
+ person.name_attributes =
554
+ { id: name.id.to_s, first_name: "Bob" }
555
+ end
556
+
557
+ it "updates the existing document" do
558
+ expect(person.name.first_name).to eq("Bob")
559
+ end
560
+ end
561
+
562
+ context "when passed keys as strings" do
563
+
564
+ before do
565
+ person.name_attributes =
566
+ { "id" => name.id.to_s, "first_name" => "Bob" }
567
+ end
568
+
569
+ it "updates the existing document" do
570
+ expect(person.name.first_name).to eq("Bob")
571
+ end
572
+ end
573
+
574
+ context "when allow_destroy is true" do
575
+
576
+ before do
577
+ Person.send(:undef_method, :name_attributes=)
578
+ Person.accepts_nested_attributes_for :name, allow_destroy: true
579
+ end
580
+
581
+ after do
582
+ Person.send(:undef_method, :name_attributes=)
583
+ Person.accepts_nested_attributes_for :name
584
+ end
585
+
586
+ [ 1, "1", true, "true" ].each do |truth|
587
+
588
+ context "when passed #{truth} with destroy" do
589
+
590
+ context "when the document has no callbacks" do
591
+
592
+ before do
593
+ person.name_attributes =
594
+ { id: name.id, _destroy: truth }
595
+ end
596
+
597
+ it "destroys the existing document" do
598
+ expect(person.name).to be_nil
599
+ end
600
+ end
601
+
602
+ context "when the document has destroy callbacks" do
603
+
604
+ before do
605
+ PetOwner.accepts_nested_attributes_for :pet, allow_destroy: true
606
+ end
607
+
608
+ after do
609
+ PetOwner.send(:undef_method, :pet_attributes=)
610
+ end
611
+
612
+ let(:owner) do
613
+ PetOwner.create!
614
+ end
615
+
616
+ let!(:pet) do
617
+ owner.create_pet
618
+ end
619
+
620
+ before do
621
+ owner.pet_attributes = { id: pet.id, _destroy: truth }
622
+ owner.save!
623
+ end
624
+
625
+ it "destroys the existing document" do
626
+ expect(owner.pet).to be_nil
627
+ end
628
+
629
+ it "runs the destroy callbacks" do
630
+ expect(pet.destroy_flag).to be true
631
+ end
632
+ end
633
+ end
634
+ end
635
+
636
+ [ nil, 0, "0", false, "false" ].each do |falsehood|
637
+
638
+ context "when passed #{falsehood} with destroy" do
639
+
640
+ before do
641
+ person.name_attributes =
642
+ { id: name.id, _destroy: falsehood }
643
+ end
644
+
645
+ it "does not destroy the existing document" do
646
+ expect(person.name).to eq(name)
647
+ end
648
+ end
649
+ end
650
+ end
651
+
652
+ context "when allow destroy is false" do
653
+
654
+ before do
655
+ Person.send(:undef_method, :name_attributes=)
656
+ Person.accepts_nested_attributes_for :name, allow_destroy: false
657
+ end
658
+
659
+ after do
660
+ Person.send(:undef_method, :name_attributes=)
661
+ Person.accepts_nested_attributes_for :name
662
+ end
663
+
664
+ context "when a destroy attribute is passed" do
665
+
666
+ before do
667
+ person.name_attributes =
668
+ { id: name.id, _destroy: true }
669
+ end
670
+
671
+ it "does not destroy the document" do
672
+ expect(person.name).to eq(name)
673
+ end
674
+ end
675
+ end
676
+
677
+ context "when update only is true" do
678
+
679
+ before do
680
+ Person.send(:undef_method, :name_attributes=)
681
+ Person.accepts_nested_attributes_for \
682
+ :name,
683
+ update_only: true,
684
+ allow_destroy: true
685
+ end
686
+
687
+ after do
688
+ Person.send(:undef_method, :name_attributes=)
689
+ Person.accepts_nested_attributes_for :name
690
+ end
691
+
692
+ context "when the id matches" do
693
+
694
+ before do
695
+ person.name_attributes =
696
+ { id: name.id, first_name: "Ro" }
697
+ end
698
+
699
+ it "updates the existing document" do
700
+ expect(person.name.first_name).to eq("Ro")
701
+ end
702
+ end
703
+
704
+ context "when the id does not match" do
705
+
706
+ before do
707
+ person.name_attributes =
708
+ { id: BSON::ObjectId.new.to_s, first_name: "Durran" }
709
+ end
710
+
711
+ it "updates the existing document" do
712
+ expect(person.name.first_name).to eq("Durran")
713
+ end
714
+ end
715
+
716
+ context "when passed a destroy truth" do
717
+
718
+ before do
719
+ person.name_attributes =
720
+ { id: name.id, _destroy: true }
721
+ end
722
+
723
+ it "destroys the existing document" do
724
+ expect(person.name).to be_nil
725
+ end
726
+ end
727
+ end
728
+
729
+ context "when ids are ObjectId strings" do
730
+
731
+ let(:quiz) do
732
+ person.quiz = Quiz.new(topic: "Math")
733
+ end
734
+
735
+ before do
736
+ person.quiz_attributes = {
737
+ "id" => quiz.id.to_s, topic: "English"
738
+ }
739
+ end
740
+
741
+ it "updates the existing document" do
742
+ expect(person.quiz.topic).to eq("English")
743
+ end
744
+ end
745
+ end
746
+ end
747
+ end
748
+
749
+ context "when the nested document is invalid" do
750
+
751
+ before do
752
+ Person.validates_associated(:pet)
753
+ end
754
+
755
+ after do
756
+ Person.reset_callbacks(:validate)
757
+ end
758
+
759
+ before do
760
+ person.pet_attributes = { name: "$$$" }
761
+ end
762
+
763
+ it "propagates invalidity to parent" do
764
+ expect(person.pet).to_not be_valid
765
+ expect(person).to_not be_valid
766
+ end
767
+ end
768
+
769
+ context "when a type is passed" do
770
+
771
+ let(:canvas) do
772
+ Canvas.new
773
+ end
774
+
775
+ before do
776
+ Canvas.send(:undef_method, :writer_attributes=)
777
+ Canvas.accepts_nested_attributes_for :writer
778
+ canvas.writer_attributes = { _type: "HtmlWriter" }
779
+ end
780
+
781
+ it "instantiates an object of the given type" do
782
+ expect(canvas.writer.class).to eq(HtmlWriter)
783
+ end
784
+ end
785
+ end
786
+
787
+ context "when the relation is embedded in" do
788
+
789
+ context "when the child is new" do
790
+
791
+ let(:animal) do
792
+ Animal.new
793
+ end
794
+
795
+ context "when no id has been passed" do
796
+
797
+ context "when no destroy attribute passed" do
798
+
799
+ before do
800
+ animal.person_attributes = { title: "Sir" }
801
+ end
802
+
803
+ it "builds a new document" do
804
+ expect(animal.person.title).to eq("Sir")
805
+ end
806
+
807
+ end
808
+
809
+ context "when a destroy attribute is passed" do
810
+
811
+ context "when allow_destroy is true" do
812
+
813
+ before do
814
+ Animal.send(:undef_method, :person_attributes=)
815
+ Animal.accepts_nested_attributes_for :person, allow_destroy: true
816
+ end
817
+
818
+ after do
819
+ Animal.send(:undef_method, :person_attributes=)
820
+ Animal.accepts_nested_attributes_for :person
821
+ end
822
+
823
+ before do
824
+ animal.person_attributes = { title: "Sir", _destroy: 1 }
825
+ end
826
+
827
+ it "does not build a new document" do
828
+ expect(animal.person).to be_nil
829
+ end
830
+ end
831
+
832
+ context "when allow_destroy is false" do
833
+
834
+ before do
835
+ Animal.send(:undef_method, :person_attributes=)
836
+ Animal.accepts_nested_attributes_for :person, allow_destroy: false
837
+ end
838
+
839
+ after do
840
+ Animal.send(:undef_method, :person_attributes=)
841
+ Animal.accepts_nested_attributes_for :person
842
+ end
843
+
844
+ before do
845
+ animal.person_attributes = { title: "Sir", _destroy: 1 }
846
+ end
847
+
848
+ it "builds a new document" do
849
+ expect(animal.person.title).to eq("Sir")
850
+ end
851
+ end
852
+ end
853
+ end
854
+
855
+ context "when an id has been passed" do
856
+
857
+ let(:person) do
858
+ Person.new
859
+ end
860
+
861
+ context "when no destroy attribute passed" do
862
+
863
+ context "when the id matches" do
864
+
865
+ before do
866
+ animal.person_attributes = { id: person.id, title: "Sir" }
867
+ end
868
+
869
+ it "updates the existing document" do
870
+ expect(animal.person.title).to eq("Sir")
871
+ end
872
+ end
873
+ end
874
+
875
+ context "when there is an existing document" do
876
+
877
+ before do
878
+ animal.person = person
879
+ end
880
+
881
+ context "when allow destroy is true" do
882
+
883
+ before do
884
+ Animal.send(:undef_method, :person_attributes=)
885
+ Animal.accepts_nested_attributes_for :person, allow_destroy: true
886
+ end
887
+
888
+ after do
889
+ Animal.send(:undef_method, :person_attributes=)
890
+ Animal.accepts_nested_attributes_for :person
891
+ end
892
+
893
+ [ 1, "1", true, "true" ].each do |truth|
894
+
895
+ context "when passed #{truth} with destroy" do
896
+
897
+ before do
898
+ animal.person_attributes =
899
+ { id: person.id, _destroy: truth }
900
+ end
901
+
902
+ it "destroys the existing document" do
903
+ expect(animal.person).to be_nil
904
+ end
905
+ end
906
+ end
907
+
908
+ [ nil, 0, "0", false, "false" ].each do |falsehood|
909
+
910
+ context "when passed #{falsehood} with destroy" do
911
+
912
+ before do
913
+ animal.person_attributes =
914
+ { id: person.id, _destroy: falsehood }
915
+ end
916
+
917
+ it "does not destroy the existing document" do
918
+ expect(animal.person).to eq(person)
919
+ end
920
+ end
921
+ end
922
+ end
923
+
924
+ context "when allow destroy is false" do
925
+
926
+ before do
927
+ Animal.send(:undef_method, :person_attributes=)
928
+ Animal.accepts_nested_attributes_for :person, allow_destroy: false
929
+ end
930
+
931
+ after do
932
+ Animal.send(:undef_method, :person_attributes=)
933
+ Animal.accepts_nested_attributes_for :person
934
+ end
935
+
936
+ context "when a destroy attribute is passed" do
937
+
938
+ before do
939
+ animal.person_attributes =
940
+ { id: person.id, _destroy: true }
941
+ end
942
+
943
+ it "does not delete the document" do
944
+ expect(animal.person).to eq(person)
945
+ end
946
+ end
947
+ end
948
+
949
+ context "when update only is true" do
950
+
951
+ before do
952
+ Animal.send(:undef_method, :person_attributes=)
953
+ Animal.accepts_nested_attributes_for \
954
+ :person,
955
+ update_only: true,
956
+ allow_destroy: true
957
+ end
958
+
959
+ context "when the id matches" do
960
+
961
+ before do
962
+ animal.person_attributes =
963
+ { id: person.id, title: "Madam" }
964
+ end
965
+
966
+ it "updates the existing document" do
967
+ expect(animal.person.title).to eq("Madam")
968
+ end
969
+ end
970
+
971
+ context "when the id does not match" do
972
+
973
+ before do
974
+ animal.person_attributes =
975
+ { id: BSON::ObjectId.new.to_s, title: "Madam" }
976
+ end
977
+
978
+ it "updates the existing document" do
979
+ expect(animal.person.title).to eq("Madam")
980
+ end
981
+ end
982
+
983
+ context "when passed a destroy truth" do
984
+
985
+ before do
986
+ animal.person_attributes =
987
+ { id: person.id, title: "Madam", _destroy: "true" }
988
+ end
989
+
990
+ it "deletes the existing document" do
991
+ expect(animal.person).to be_nil
992
+ end
993
+ end
994
+ end
995
+ end
996
+ end
997
+
998
+ context "when the nested document is invalid" do
999
+
1000
+ before do
1001
+ Person.validates_format_of :ssn, without: /\$\$\$/
1002
+ end
1003
+
1004
+ after do
1005
+ Person.reset_callbacks(:validate)
1006
+ end
1007
+
1008
+ before do
1009
+ animal.person_attributes = { ssn: '$$$' }
1010
+ end
1011
+
1012
+ it "does not propagate invalidity to parent" do
1013
+ expect(animal.person).to_not be_valid
1014
+ expect(animal).to be_valid
1015
+ end
1016
+ end
1017
+ end
1018
+
1019
+ context "when a type is passed" do
1020
+
1021
+ let(:tool) do
1022
+ Tool.new
1023
+ end
1024
+
1025
+ before do
1026
+ tool.palette_attributes ={ _type: "BigPalette" }
1027
+ end
1028
+
1029
+ it "instantiates an object of the given type" do
1030
+ expect(tool.palette.class).to eq(BigPalette)
1031
+ end
1032
+ end
1033
+ end
1034
+
1035
+ context "when the relation is an embeds many" do
1036
+
1037
+ context "when the parent document is persisted" do
1038
+
1039
+ let(:person) do
1040
+ Person.create!
1041
+ end
1042
+
1043
+ before do
1044
+ Person.send(:undef_method, :addresses_attributes=)
1045
+ Person.accepts_nested_attributes_for :addresses
1046
+ end
1047
+
1048
+ after do
1049
+ Person.send(:undef_method, :addresses_attributes=)
1050
+ Person.accepts_nested_attributes_for :addresses
1051
+ end
1052
+
1053
+ context "when setting the child attributes" do
1054
+
1055
+ let(:attributes) do
1056
+ { "foo" => { "street" => "Maybachufer" } }
1057
+ end
1058
+
1059
+ before do
1060
+ person.addresses_attributes = attributes
1061
+ end
1062
+
1063
+ it "sets the child documents" do
1064
+ expect(person.addresses.first.street).to eq("Maybachufer")
1065
+ end
1066
+
1067
+ it "does not persist the child documents" do
1068
+ expect(person.addresses.first).to_not be_persisted
1069
+ end
1070
+
1071
+ context "when saving the parent" do
1072
+
1073
+ before do
1074
+ person.save!
1075
+ person.reload
1076
+ end
1077
+
1078
+ it "saves the child documents" do
1079
+ expect(person.addresses.first).to be_persisted
1080
+ end
1081
+ end
1082
+ end
1083
+ end
1084
+
1085
+ let(:person) do
1086
+ Person.new
1087
+ end
1088
+
1089
+ let(:address_one) do
1090
+ Address.new(street: "Unter den Linden")
1091
+ end
1092
+
1093
+ let(:address_two) do
1094
+ Address.new(street: "Kurfeurstendamm")
1095
+ end
1096
+
1097
+ context "when a limit is specified" do
1098
+
1099
+ before do
1100
+ Person.send(:undef_method, :addresses_attributes=)
1101
+ Person.accepts_nested_attributes_for :addresses, limit: 2
1102
+ end
1103
+
1104
+ after do
1105
+ Person.send(:undef_method, :addresses_attributes=)
1106
+ Person.accepts_nested_attributes_for :addresses
1107
+ end
1108
+
1109
+ context "when more are provided than the limit" do
1110
+
1111
+ let(:attributes) do
1112
+ {
1113
+ "foo" => { "street" => "Maybachufer" },
1114
+ "bar" => { "street" => "Alexander Platz" },
1115
+ "baz" => { "street" => "Unter den Linden" }
1116
+ }
1117
+ end
1118
+
1119
+ it "raises an error" do
1120
+ expect {
1121
+ person.addresses_attributes = attributes
1122
+ }.to raise_error(Mongoid::Errors::TooManyNestedAttributeRecords)
1123
+ end
1124
+ end
1125
+
1126
+ context "when less are provided than the limit" do
1127
+
1128
+ let(:attributes) do
1129
+ {
1130
+ "foo" => { "street" => "Maybachufer" },
1131
+ "bar" => { "street" => "Alexander Platz" }
1132
+ }
1133
+ end
1134
+
1135
+ before do
1136
+ person.addresses_attributes = attributes
1137
+ end
1138
+
1139
+ it "sets the documents on the relation" do
1140
+ expect(person.addresses.size).to eq(2)
1141
+ end
1142
+ end
1143
+
1144
+ context "when an array of attributes are passed" do
1145
+
1146
+ let(:attributes) do
1147
+ [
1148
+ { "street" => "Maybachufer" },
1149
+ { "street" => "Alexander Platz" }
1150
+ ]
1151
+ end
1152
+
1153
+ before do
1154
+ person.addresses_attributes = attributes
1155
+ end
1156
+
1157
+ it "sets the documents on the relation" do
1158
+ expect(person.addresses.size).to eq(2)
1159
+ end
1160
+ end
1161
+
1162
+ context "when cascading callbacks" do
1163
+
1164
+ before do
1165
+ Band.accepts_nested_attributes_for :records
1166
+ end
1167
+
1168
+ after do
1169
+ Band.send(:undef_method, :records_attributes=)
1170
+ end
1171
+
1172
+ let(:band) do
1173
+ Band.new
1174
+ end
1175
+
1176
+ let(:attributes) do
1177
+ [
1178
+ { "name" => "101" },
1179
+ { "name" => "Ultra" }
1180
+ ]
1181
+ end
1182
+
1183
+ before do
1184
+ band.records_attributes = attributes
1185
+ end
1186
+
1187
+ context "when the parent is saved" do
1188
+
1189
+ before do
1190
+ band.save!
1191
+ end
1192
+
1193
+ it "runs the first child create callbacks" do
1194
+ expect(band.records.first.before_create_called).to be true
1195
+ end
1196
+
1197
+ it "runs the last child create callbacks" do
1198
+ expect(band.records.last.before_create_called).to be true
1199
+ end
1200
+ end
1201
+ end
1202
+ end
1203
+
1204
+ context "when ids are passed" do
1205
+
1206
+ before do
1207
+ person.addresses << [ address_one, address_two ]
1208
+ end
1209
+
1210
+ context "when no destroy attributes are passed" do
1211
+
1212
+ context "when the ids match" do
1213
+
1214
+ before do
1215
+ person.addresses_attributes =
1216
+ {
1217
+ "foo" => { "id" => address_one.id, "street" => "Maybachufer" },
1218
+ "bar" => { "id" => address_two.id, "street" => "Alexander Platz" }
1219
+ }
1220
+ end
1221
+
1222
+ it "updates the first existing document" do
1223
+ expect(person.addresses.first.street).to eq("Maybachufer")
1224
+ end
1225
+
1226
+ it "updates the second existing document" do
1227
+ expect(person.addresses.second.street).to eq("Alexander Platz")
1228
+ end
1229
+
1230
+ it "does not add new documents" do
1231
+ expect(person.addresses.size).to eq(2)
1232
+ end
1233
+ end
1234
+
1235
+ context "when the ids match in an array of attributes" do
1236
+
1237
+ context "when passing in id" do
1238
+
1239
+ before do
1240
+ person.addresses_attributes =
1241
+ [
1242
+ { "id" => address_one.id, "street" => "Maybachufer" },
1243
+ { "id" => address_two.id, "street" => "Alexander Platz" }
1244
+ ]
1245
+ end
1246
+
1247
+ it "updates the first existing document" do
1248
+ expect(person.addresses.collect { |a| a['street'] }).to include('Maybachufer')
1249
+ end
1250
+
1251
+ it "updates the second existing document" do
1252
+ expect(person.addresses.collect { |a| a['street'] }).to include('Alexander Platz')
1253
+ end
1254
+
1255
+ it "does not add new documents" do
1256
+ expect(person.addresses.size).to eq(2)
1257
+ end
1258
+ end
1259
+
1260
+ context "when passing in _id" do
1261
+
1262
+ before do
1263
+ person.addresses_attributes =
1264
+ [
1265
+ { "_id" => address_one.id, "street" => "Maybachufer" },
1266
+ { "_id" => address_two.id, "street" => "Alexander Platz" }
1267
+ ]
1268
+ end
1269
+
1270
+ it "updates the first existing document" do
1271
+ expect(person.addresses.collect { |a| a['street'] }).to include('Maybachufer')
1272
+ end
1273
+
1274
+ it "updates the second existing document" do
1275
+ expect(person.addresses.collect { |a| a['street'] }).to include('Alexander Platz')
1276
+ end
1277
+
1278
+ it "does not add new documents" do
1279
+ expect(person.addresses.size).to eq(2)
1280
+ end
1281
+ end
1282
+ end
1283
+
1284
+ context "when the ids match in an array of attributes and start with '_'" do
1285
+
1286
+ before do
1287
+ person.addresses_attributes =
1288
+ [
1289
+ { "_id" => address_one.id, "street" => "Maybachufer" },
1290
+ { "_id" => address_two.id, "street" => "Alexander Platz" }
1291
+ ]
1292
+ end
1293
+
1294
+ it "updates the first existing document" do
1295
+ expect(person.addresses.collect { |a| a['street'] }).to include('Maybachufer')
1296
+ end
1297
+
1298
+ it "updates the second existing document" do
1299
+ expect(person.addresses.collect { |a| a['street'] }).to include('Alexander Platz')
1300
+ end
1301
+
1302
+ it "does not add new documents" do
1303
+ expect(person.addresses.size).to eq(2)
1304
+ end
1305
+ end
1306
+
1307
+ context "when the ids are _id symbols" do
1308
+
1309
+ before do
1310
+ person.addresses_attributes =
1311
+ [
1312
+ { _id: address_one.id, "street" => "Maybachufer" },
1313
+ { _id: address_two.id, "street" => "Alexander Platz" }
1314
+ ]
1315
+ end
1316
+
1317
+ it "updates the first existing document" do
1318
+ expect(person.addresses.collect { |a| a['street'] }).to include('Maybachufer')
1319
+ end
1320
+
1321
+ it "updates the second existing document" do
1322
+ expect(person.addresses.collect { |a| a['street'] }).to include('Alexander Platz')
1323
+ end
1324
+
1325
+ it "does not add new documents" do
1326
+ expect(person.addresses.size).to eq(2)
1327
+ end
1328
+ end
1329
+
1330
+ context "when the ids are id symbols" do
1331
+
1332
+ before do
1333
+ person.addresses_attributes =
1334
+ [
1335
+ { id: address_one.id, "street" => "Maybachufer" },
1336
+ { id: address_two.id, "street" => "Alexander Platz" }
1337
+ ]
1338
+ end
1339
+
1340
+ it "updates the first existing document" do
1341
+ expect(person.addresses.collect { |a| a['street'] }).to include('Maybachufer')
1342
+ end
1343
+
1344
+ it "updates the second existing document" do
1345
+ expect(person.addresses.collect { |a| a['street'] }).to include('Alexander Platz')
1346
+ end
1347
+
1348
+ it "does not add new documents" do
1349
+ expect(person.addresses.size).to eq(2)
1350
+ end
1351
+ end
1352
+
1353
+ context "when the ids do not match" do
1354
+
1355
+ it "raises an error" do
1356
+ expect {
1357
+ person.addresses_attributes =
1358
+ { "foo" => { "id" => "test", "street" => "Test" } }
1359
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Address with id\(s\)/)
1360
+ end
1361
+ end
1362
+ end
1363
+
1364
+ context "when destroy attributes are passed" do
1365
+
1366
+ context "when the ids match" do
1367
+
1368
+ context "when allow_destroy is true" do
1369
+
1370
+ context "when the parent validation failed" do
1371
+
1372
+ class BandWithAllowDestroyedRecords < Band
1373
+ validates_presence_of :name
1374
+ accepts_nested_attributes_for :records, :allow_destroy => true
1375
+ end
1376
+
1377
+ let!(:band) do
1378
+ BandWithAllowDestroyedRecords.create(name: "Depeche Mode")
1379
+ end
1380
+
1381
+ let!(:record) do
1382
+ band.records.create!
1383
+ end
1384
+
1385
+ let(:attributes) do
1386
+ {
1387
+ name: nil,
1388
+ records_attributes: { "foo" => { "id" => record.id, "_destroy" => true }}
1389
+ }
1390
+ end
1391
+
1392
+ before do
1393
+ band.update_attributes(attributes)
1394
+ end
1395
+
1396
+ it "does not remove the child document" do
1397
+ expect(band.records).to_not be_empty
1398
+ end
1399
+
1400
+ it "keeps the child flagged for destruction" do
1401
+ expect(record).to be_flagged_for_destroy
1402
+ end
1403
+
1404
+ it "does not persist any change" do
1405
+ expect(band.reload.records).to eq([ record ])
1406
+ end
1407
+ end
1408
+
1409
+ context "when the child accesses the parent after destroy" do
1410
+
1411
+ before do
1412
+ Band.accepts_nested_attributes_for :records, :allow_destroy => true
1413
+ end
1414
+
1415
+ after do
1416
+ Band.send(:undef_method, :records_attributes=)
1417
+ end
1418
+
1419
+ let!(:band) do
1420
+ Band.create!
1421
+ end
1422
+
1423
+ let!(:record) do
1424
+ band.records.create!
1425
+ end
1426
+
1427
+ before do
1428
+ band.records_attributes =
1429
+ { "foo" => { "id" => record.id, "_destroy" => true }}
1430
+ band.save!
1431
+ end
1432
+
1433
+ it "deletes the child document" do
1434
+ expect(band.records).to be_empty
1435
+ end
1436
+
1437
+ it "persists the changes" do
1438
+ expect(band.reload.records).to be_empty
1439
+ end
1440
+ end
1441
+
1442
+ context "when the child has defaults" do
1443
+
1444
+ before do
1445
+ Person.accepts_nested_attributes_for :appointments, allow_destroy: true
1446
+ end
1447
+
1448
+ after do
1449
+ Person.send(:undef_method, :appointments_attributes=)
1450
+ end
1451
+
1452
+ context "when the parent is persisted" do
1453
+
1454
+ let!(:persisted) do
1455
+ Person.create!(age: 42)
1456
+ end
1457
+
1458
+ context "when the child halts the callback chain in a before callback" do
1459
+
1460
+ context "when the child is not paranoid" do
1461
+
1462
+ let(:actor) do
1463
+ Actor.create!
1464
+ end
1465
+
1466
+ let!(:thing) do
1467
+ actor.things.create!
1468
+ end
1469
+
1470
+ before do
1471
+ actor.things_attributes =
1472
+ { "foo" => { "id" => thing.id, "_destroy" => true }}
1473
+ actor.save
1474
+ end
1475
+
1476
+ it "does not destroy the child" do
1477
+ expect(actor.reload.things).to_not be_empty
1478
+ end
1479
+ end
1480
+ end
1481
+
1482
+ context "when only 1 child has the default persisted" do
1483
+
1484
+ let!(:app_one) do
1485
+ persisted.appointments.create!
1486
+ end
1487
+
1488
+ let!(:app_two) do
1489
+ persisted.appointments.create!.tap do |app|
1490
+ app.unset(:timed)
1491
+ end
1492
+ end
1493
+
1494
+ context "when destroying both children" do
1495
+
1496
+ let(:from_db) do
1497
+ Person.find(persisted.id)
1498
+ end
1499
+
1500
+ before do
1501
+ from_db.appointments_attributes =
1502
+ {
1503
+ "bar" => { "id" => app_one.id, "_destroy" => true },
1504
+ "foo" => { "id" => app_two.id, "_destroy" => true }
1505
+ }
1506
+ from_db.save!
1507
+ end
1508
+
1509
+ it "destroys both children" do
1510
+ expect(from_db.appointments).to be_empty
1511
+ end
1512
+
1513
+ it "persists the deletes" do
1514
+ expect(from_db.reload.appointments).to be_empty
1515
+ end
1516
+ end
1517
+ end
1518
+ end
1519
+ end
1520
+
1521
+ context "when the child is not paranoid" do
1522
+
1523
+ before do
1524
+ Person.send(:undef_method, :addresses_attributes=)
1525
+ Person.accepts_nested_attributes_for :addresses, allow_destroy: true
1526
+ end
1527
+
1528
+ after do
1529
+ Person.send(:undef_method, :addresses_attributes=)
1530
+ Person.accepts_nested_attributes_for :addresses
1531
+ end
1532
+
1533
+ [ 1, "1", true, "true" ].each do |truth|
1534
+
1535
+ context "when passed a #{truth} with destroy" do
1536
+
1537
+ context "when the parent is new" do
1538
+
1539
+ context "when provided a hash of attributes" do
1540
+
1541
+ before do
1542
+ person.addresses_attributes =
1543
+ {
1544
+ "bar" => { "id" => address_one.id.to_s, "_destroy" => truth },
1545
+ "foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
1546
+ }
1547
+ end
1548
+
1549
+ it "deletes the marked document" do
1550
+ expect(person.addresses.size).to eq(1)
1551
+ end
1552
+
1553
+ it "does not delete the unmarked document" do
1554
+ expect(person.addresses.first.street).to eq("Alexander Platz")
1555
+ end
1556
+ end
1557
+
1558
+ context "when provided an array of attributes" do
1559
+
1560
+ before do
1561
+ person.addresses_attributes =
1562
+ [
1563
+ { "id" => address_one.id.to_s, "_destroy" => truth },
1564
+ { "id" => address_two.id, "street" => "Alexander Platz" }
1565
+ ]
1566
+ end
1567
+
1568
+ it "deletes the marked document" do
1569
+ expect(person.addresses.size).to eq(1)
1570
+ end
1571
+
1572
+ it "does not delete the unmarked document" do
1573
+ expect(person.addresses.first.street).to eq("Alexander Platz")
1574
+ end
1575
+ end
1576
+ end
1577
+
1578
+ context "when the parent is persisted" do
1579
+
1580
+ let!(:persisted) do
1581
+ Person.create! do |p|
1582
+ p.addresses << [ address_one, address_two ]
1583
+ end
1584
+ end
1585
+
1586
+ context "when setting, pulling, and pushing in one op" do
1587
+
1588
+ before do
1589
+ persisted.addresses_attributes =
1590
+ {
1591
+ "bar" => { "id" => address_one.id, "_destroy" => truth },
1592
+ "foo" => { "id" => address_two.id, "street" => "Alexander Platz" },
1593
+ "baz" => { "street" => "Potsdammer Platz" }
1594
+ }
1595
+ end
1596
+
1597
+ it "does not remove the first document from the relation" do
1598
+ expect(persisted.addresses.size).to eq(3)
1599
+ end
1600
+
1601
+ it "flags the destroyed document for removal" do
1602
+ expect(address_one).to be_marked_for_destruction
1603
+ end
1604
+
1605
+ it "does not delete the unmarked document" do
1606
+ expect(persisted.addresses.second.street).to eq(
1607
+ "Alexander Platz"
1608
+ )
1609
+ end
1610
+
1611
+ it "adds the new document to the relation" do
1612
+ expect(persisted.addresses.last.street).to eq(
1613
+ "Potsdammer Platz"
1614
+ )
1615
+ end
1616
+
1617
+ it "has the proper persisted count" do
1618
+ expect(persisted.addresses.count).to eq(2)
1619
+ end
1620
+
1621
+ it "does not delete the removed document" do
1622
+ expect(address_one).to_not be_destroyed
1623
+ end
1624
+
1625
+ context "when saving the parent" do
1626
+
1627
+ before do
1628
+ persisted.save!
1629
+ end
1630
+
1631
+ it "deletes the marked document from the relation" do
1632
+ expect(persisted.reload.addresses.count).to eq(2)
1633
+ end
1634
+
1635
+ it "does not delete the unmarked document" do
1636
+ expect(persisted.reload.addresses.first.street).to eq(
1637
+ "Alexander Platz"
1638
+ )
1639
+ end
1640
+
1641
+ it "persists the new document to the relation" do
1642
+ expect(persisted.reload.addresses.last.street).to eq(
1643
+ "Potsdammer Platz"
1644
+ )
1645
+ end
1646
+ end
1647
+ end
1648
+
1649
+ context "when pulling and pushing in one op" do
1650
+
1651
+ before do
1652
+ persisted.addresses_attributes =
1653
+ {
1654
+ "bar" => { "id" => address_one.id, "_destroy" => truth },
1655
+ "baz" => { "street" => "Potsdammer Platz" }
1656
+ }
1657
+ end
1658
+
1659
+ it "does not remove the first document from the relation" do
1660
+ expect(persisted.addresses.size).to eq(3)
1661
+ end
1662
+
1663
+ it "marks the first document for destruction" do
1664
+ expect(address_one).to be_marked_for_destruction
1665
+ end
1666
+
1667
+ it "adds the new document to the relation" do
1668
+ expect(persisted.addresses.last.street).to eq(
1669
+ "Potsdammer Platz"
1670
+ )
1671
+ end
1672
+
1673
+ it "has the proper persisted count" do
1674
+ expect(persisted.addresses.count).to eq(2)
1675
+ end
1676
+
1677
+ it "does not delete the removed document" do
1678
+ expect(address_one).to_not be_destroyed
1679
+ end
1680
+
1681
+ context "when saving the parent" do
1682
+
1683
+ before do
1684
+ persisted.save!
1685
+ end
1686
+
1687
+ it "deletes the marked document from the relation" do
1688
+ expect(persisted.reload.addresses.count).to eq(2)
1689
+ end
1690
+
1691
+ it "persists the new document to the relation" do
1692
+ expect(persisted.reload.addresses.last.street).to eq(
1693
+ "Potsdammer Platz"
1694
+ )
1695
+ end
1696
+ end
1697
+ end
1698
+ end
1699
+ end
1700
+ end
1701
+
1702
+ [ 0, "0", false, "false" ].each do |falsehood|
1703
+
1704
+ context "when passed a #{falsehood} with destroy" do
1705
+
1706
+ before do
1707
+ person.addresses_attributes =
1708
+ {
1709
+ "bar" => { "id" => address_one.id, "_destroy" => falsehood },
1710
+ "foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
1711
+ }
1712
+ end
1713
+
1714
+ it "does not delete the marked document" do
1715
+ expect(person.addresses.size).to eq(2)
1716
+ end
1717
+
1718
+ it "does not delete the unmarked document" do
1719
+ expect(person.addresses.last.street).to eq("Alexander Platz")
1720
+ end
1721
+ end
1722
+ end
1723
+ end
1724
+ end
1725
+
1726
+ context "when allow_destroy is false" do
1727
+
1728
+ before do
1729
+ Person.send(:undef_method, :addresses_attributes=)
1730
+ Person.accepts_nested_attributes_for :addresses, allow_destroy: false
1731
+ end
1732
+
1733
+ after do
1734
+ Person.send(:undef_method, :addresses_attributes=)
1735
+ Person.accepts_nested_attributes_for :addresses
1736
+ end
1737
+
1738
+ [ 1, "1", true, "true" ].each do |truth|
1739
+
1740
+ context "when passed a #{truth} with destroy" do
1741
+
1742
+ before do
1743
+ person.addresses_attributes =
1744
+ {
1745
+ "bar" => {
1746
+ "id" => address_one.id, "street" => "Maybachufer", "_destroy" => truth },
1747
+ "foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
1748
+ }
1749
+ end
1750
+
1751
+ it "does not ignore the marked document" do
1752
+ expect(person.addresses.first.street).to eq("Maybachufer")
1753
+ end
1754
+
1755
+ it "does not delete the unmarked document" do
1756
+ expect(person.addresses.last.street).to eq("Alexander Platz")
1757
+ end
1758
+
1759
+ it "does not add additional documents" do
1760
+ expect(person.addresses.size).to eq(2)
1761
+ end
1762
+ end
1763
+ end
1764
+
1765
+ [ 0, "0", false, "false" ].each do |falsehood|
1766
+
1767
+ context "when passed a #{falsehood} with destroy" do
1768
+
1769
+ before do
1770
+ person.addresses_attributes =
1771
+ {
1772
+ "bar" => { "id" => address_one.id, "_destroy" => falsehood },
1773
+ "foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
1774
+ }
1775
+ end
1776
+
1777
+ it "does not delete the marked document" do
1778
+ expect(person.addresses.size).to eq(2)
1779
+ end
1780
+
1781
+ it "does not delete the unmarked document" do
1782
+ expect(person.addresses.last.street).to eq("Alexander Platz")
1783
+ end
1784
+ end
1785
+ end
1786
+ end
1787
+
1788
+ context "when allow_destroy is undefined" do
1789
+
1790
+ before do
1791
+ Person.send(:undef_method, :addresses_attributes=)
1792
+ Person.accepts_nested_attributes_for :addresses
1793
+ end
1794
+
1795
+ [ 1, "1", true, "true" ].each do |truth|
1796
+
1797
+ context "when passed a #{truth} with destroy" do
1798
+
1799
+ before do
1800
+ person.addresses_attributes =
1801
+ {
1802
+ "bar" => {
1803
+ "id" => address_one.id, "street" => "Maybachufer", "_destroy" => truth },
1804
+ "foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
1805
+ }
1806
+ end
1807
+
1808
+ it "does not ignore the marked document" do
1809
+ expect(person.addresses.first.street).to eq("Maybachufer")
1810
+ end
1811
+
1812
+ it "does not delete the unmarked document" do
1813
+ expect(person.addresses.last.street).to eq("Alexander Platz")
1814
+ end
1815
+
1816
+ it "does not add additional documents" do
1817
+ expect(person.addresses.size).to eq(2)
1818
+ end
1819
+ end
1820
+ end
1821
+
1822
+ [ 0, "0", false, "false" ].each do |falsehood|
1823
+
1824
+ context "when passed a #{falsehood} with destroy" do
1825
+
1826
+ before do
1827
+ person.addresses_attributes =
1828
+ {
1829
+ "bar" => { "id" => address_one.id, "_destroy" => falsehood },
1830
+ "foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
1831
+ }
1832
+ end
1833
+
1834
+ it "does not delete the marked document" do
1835
+ expect(person.addresses.size).to eq(2)
1836
+ end
1837
+
1838
+ it "does not delete the unmarked document" do
1839
+ expect(person.addresses.last.street).to eq("Alexander Platz")
1840
+ end
1841
+ end
1842
+ end
1843
+ end
1844
+ end
1845
+ end
1846
+ end
1847
+
1848
+ context "when no ids are passed" do
1849
+
1850
+ context "when no destroy attributes are passed" do
1851
+
1852
+ before do
1853
+ person.addresses_attributes =
1854
+ {
1855
+ "4" => { "street" => "Maybachufer" },
1856
+ "1" => { "street" => "Frederichstrasse" },
1857
+ "2" => { "street" => "Alexander Platz" }
1858
+ }
1859
+ end
1860
+
1861
+ it "builds a new first document" do
1862
+ expect(person.addresses.first.street).to eq("Frederichstrasse")
1863
+ end
1864
+
1865
+ it "builds a new second document" do
1866
+ expect(person.addresses.second.street).to eq("Alexander Platz")
1867
+ end
1868
+
1869
+ it "builds a new third document" do
1870
+ expect(person.addresses.third.street).to eq("Maybachufer")
1871
+ end
1872
+
1873
+ it "does not add extra documents" do
1874
+ expect(person.addresses.size).to eq(3)
1875
+ end
1876
+
1877
+ it "adds the documents in the sorted hash key order" do
1878
+ expect(person.addresses.map(&:street)).to eq(
1879
+ [ "Frederichstrasse", "Alexander Platz", "Maybachufer" ]
1880
+ )
1881
+ end
1882
+ end
1883
+
1884
+ context "when a reject block is supplied" do
1885
+
1886
+ before do
1887
+ Person.send(:undef_method, :addresses_attributes=)
1888
+ Person.accepts_nested_attributes_for \
1889
+ :addresses, reject_if: ->(attrs){ attrs["street"].blank? }
1890
+ end
1891
+
1892
+ after do
1893
+ Person.send(:undef_method, :addresses_attributes=)
1894
+ Person.accepts_nested_attributes_for :addresses
1895
+ end
1896
+
1897
+ context "when the attributes match" do
1898
+
1899
+ before do
1900
+ person.addresses_attributes =
1901
+ { "3" => { "city" => "Berlin" } }
1902
+ end
1903
+
1904
+ it "does not add the new document" do
1905
+ expect(person.addresses).to be_empty
1906
+ end
1907
+ end
1908
+
1909
+ context "when the attributes do not match" do
1910
+
1911
+ before do
1912
+ person.addresses_attributes =
1913
+ { "3" => { "street" => "Maybachufer" } }
1914
+ end
1915
+
1916
+ it "adds the new document" do
1917
+ expect(person.addresses.size).to eq(1)
1918
+ end
1919
+
1920
+ it "sets the correct attributes" do
1921
+ expect(person.addresses.first.street).to eq("Maybachufer")
1922
+ end
1923
+ end
1924
+ end
1925
+
1926
+ context "when :reject_if => :all_blank is supplied" do
1927
+
1928
+ before do
1929
+ Person.send(:undef_method, :addresses_attributes=)
1930
+ Person.accepts_nested_attributes_for \
1931
+ :addresses, reject_if: :all_blank
1932
+ end
1933
+
1934
+ after do
1935
+ Person.send(:undef_method, :addresses_attributes=)
1936
+ Person.accepts_nested_attributes_for :addresses
1937
+ end
1938
+
1939
+ context "when all attributes are empty" do
1940
+
1941
+ before do
1942
+ person.addresses_attributes =
1943
+ { "3" => { "city" => "" } }
1944
+ end
1945
+
1946
+ it "does not add the new document" do
1947
+ expect(person.addresses).to be_empty
1948
+ end
1949
+ end
1950
+
1951
+ context "when an attribute is not-empty" do
1952
+
1953
+ before do
1954
+ person.addresses_attributes =
1955
+ { "3" => { "street" => "Maybachufer" } }
1956
+ end
1957
+
1958
+ it "adds the new document" do
1959
+ expect(person.addresses.size).to eq(1)
1960
+ end
1961
+
1962
+ it "sets the correct attributes" do
1963
+ expect(person.addresses.first.street).to eq("Maybachufer")
1964
+ end
1965
+ end
1966
+ end
1967
+
1968
+ context "when destroy attributes are passed" do
1969
+
1970
+ context "when allow_destroy is true" do
1971
+
1972
+ before do
1973
+ Person.send(:undef_method, :addresses_attributes=)
1974
+ Person.accepts_nested_attributes_for :addresses, allow_destroy: true
1975
+ end
1976
+
1977
+ after do
1978
+ Person.send(:undef_method, :addresses_attributes=)
1979
+ Person.accepts_nested_attributes_for :addresses
1980
+ end
1981
+
1982
+ [ 1, "1", true, "true" ].each do |truth|
1983
+
1984
+ context "when passed a #{truth} with destroy" do
1985
+
1986
+ before do
1987
+ person.addresses_attributes =
1988
+ {
1989
+ "bar" => { "street" => "Maybachufer", "_destroy" => truth },
1990
+ "foo" => { "street" => "Alexander Platz" }
1991
+ }
1992
+ end
1993
+
1994
+ it "ignores the marked document" do
1995
+ expect(person.addresses.size).to eq(1)
1996
+ end
1997
+
1998
+ it "adds the new unmarked document" do
1999
+ expect(person.addresses.first.street).to eq("Alexander Platz")
2000
+ end
2001
+ end
2002
+ end
2003
+
2004
+ [ 0, "0", false, "false" ].each do |falsehood|
2005
+
2006
+ context "when passed a #{falsehood} with destroy" do
2007
+
2008
+ before do
2009
+ person.addresses_attributes =
2010
+ {
2011
+ "0" => { "street" => "Maybachufer", "_destroy" => falsehood },
2012
+ "1" => { "street" => "Alexander Platz" }
2013
+ }
2014
+ end
2015
+
2016
+ it "adds the new marked document" do
2017
+ expect(person.addresses.first.street).to eq("Maybachufer")
2018
+ end
2019
+
2020
+ it "adds the new unmarked document" do
2021
+ expect(person.addresses.last.street).to eq("Alexander Platz")
2022
+ end
2023
+
2024
+ it "does not add extra documents" do
2025
+ expect(person.addresses.size).to eq(2)
2026
+ end
2027
+ end
2028
+ end
2029
+ end
2030
+
2031
+ context "when allow destroy is false" do
2032
+
2033
+ before do
2034
+ Person.send(:undef_method, :addresses_attributes=)
2035
+ Person.accepts_nested_attributes_for :addresses, allow_destroy: false
2036
+ end
2037
+
2038
+ after do
2039
+ Person.send(:undef_method, :addresses_attributes=)
2040
+ Person.accepts_nested_attributes_for :addresses
2041
+ end
2042
+
2043
+ [ 1, "1", true, "true" ].each do |truth|
2044
+
2045
+ context "when passed a #{truth} with destroy" do
2046
+
2047
+ before do
2048
+ person.addresses_attributes =
2049
+ {
2050
+ "0" => { "street" => "Maybachufer", "_destroy" => truth },
2051
+ "1" => { "street" => "Alexander Platz" }
2052
+ }
2053
+ end
2054
+
2055
+ it "adds the marked document" do
2056
+ expect(person.addresses.first.street).to eq("Maybachufer")
2057
+ end
2058
+
2059
+ it "adds the new unmarked document" do
2060
+ expect(person.addresses.last.street).to eq("Alexander Platz")
2061
+ end
2062
+
2063
+ it "adds the correct number of documents" do
2064
+ expect(person.addresses.size).to eq(2)
2065
+ end
2066
+ end
2067
+ end
2068
+
2069
+ [ 0, "0", false, "false" ].each do |falsehood|
2070
+
2071
+ context "when passed a #{falsehood} with destroy" do
2072
+
2073
+ before do
2074
+ person.addresses_attributes =
2075
+ {
2076
+ "0" => { "street" => "Maybachufer", "_destroy" => falsehood },
2077
+ "1" => { "street" => "Alexander Platz" }
2078
+ }
2079
+ end
2080
+
2081
+ it "adds the new marked document" do
2082
+ expect(person.addresses.first.street).to eq("Maybachufer")
2083
+ end
2084
+
2085
+ it "adds the new unmarked document" do
2086
+ expect(person.addresses.last.street).to eq("Alexander Platz")
2087
+ end
2088
+
2089
+ it "does not add extra documents" do
2090
+ expect(person.addresses.size).to eq(2)
2091
+ end
2092
+ end
2093
+ end
2094
+ end
2095
+
2096
+ context "when allow destroy is not defined" do
2097
+
2098
+ before do
2099
+ Person.send(:undef_method, :addresses_attributes=)
2100
+ Person.accepts_nested_attributes_for :addresses
2101
+ end
2102
+
2103
+ [ 1, "1", true, "true" ].each do |truth|
2104
+
2105
+ context "when passed a #{truth} with destroy" do
2106
+
2107
+ before do
2108
+ person.addresses_attributes =
2109
+ {
2110
+ "0" => { "street" => "Maybachufer", "_destroy" => truth },
2111
+ "1" => { "street" => "Alexander Platz" }
2112
+ }
2113
+ end
2114
+
2115
+ it "adds the marked document" do
2116
+ expect(person.addresses.first.street).to eq("Maybachufer")
2117
+ end
2118
+
2119
+ it "adds the new unmarked document" do
2120
+ expect(person.addresses.last.street).to eq("Alexander Platz")
2121
+ end
2122
+
2123
+ it "adds the correct number of documents" do
2124
+ expect(person.addresses.size).to eq(2)
2125
+ end
2126
+ end
2127
+ end
2128
+
2129
+ [ 0, "0", false, "false" ].each do |falsehood|
2130
+
2131
+ context "when passed a #{falsehood} with destroy" do
2132
+
2133
+ before do
2134
+ person.addresses_attributes =
2135
+ {
2136
+ "0" => { "street" => "Maybachufer", "_destroy" => falsehood },
2137
+ "1" => { "street" => "Alexander Platz" }
2138
+ }
2139
+ end
2140
+
2141
+ it "adds the new marked document" do
2142
+ expect(person.addresses.first.street).to eq("Maybachufer")
2143
+ end
2144
+
2145
+ it "adds the new unmarked document" do
2146
+ expect(person.addresses.last.street).to eq("Alexander Platz")
2147
+ end
2148
+
2149
+ it "does not add extra documents" do
2150
+ expect(person.addresses.size).to eq(2)
2151
+ end
2152
+ end
2153
+ end
2154
+ end
2155
+ end
2156
+
2157
+ context "when 'reject_if: :all_blank' and 'allow_destroy: true' are specified" do
2158
+
2159
+ before do
2160
+ Person.send(:undef_method, :addresses_attributes=)
2161
+ Person.accepts_nested_attributes_for \
2162
+ :addresses, reject_if: :all_blank, allow_destroy: true
2163
+ end
2164
+
2165
+ after do
2166
+ Person.send(:undef_method, :addresses_attributes=)
2167
+ Person.accepts_nested_attributes_for :addresses
2168
+ end
2169
+
2170
+ context "when all attributes are blank and _destroy has a truthy, non-blank value" do
2171
+
2172
+ before do
2173
+ person.addresses_attributes =
2174
+ { "3" => { last_name: "", _destroy: "0" } }
2175
+ end
2176
+
2177
+ it "does not add the document" do
2178
+ expect(person.addresses).to be_empty
2179
+ end
2180
+ end
2181
+ end
2182
+ end
2183
+
2184
+ context "when the nested document is invalid" do
2185
+
2186
+ before do
2187
+ Person.validates_associated(:addresses)
2188
+ end
2189
+
2190
+ after do
2191
+ Person.reset_callbacks(:validate)
2192
+ end
2193
+
2194
+ before do
2195
+ person.addresses_attributes = {
2196
+ "0" => { street: '123' }
2197
+ }
2198
+ end
2199
+
2200
+ it "propagates invalidity to parent" do
2201
+ expect(person.addresses.first).to_not be_valid
2202
+ expect(person).to_not be_valid
2203
+ end
2204
+ end
2205
+
2206
+ context "when a type is passed" do
2207
+
2208
+ let(:canvas) do
2209
+ Canvas.new
2210
+ end
2211
+
2212
+ before do
2213
+ Canvas.send(:undef_method, :shapes_attributes=)
2214
+ Canvas.accepts_nested_attributes_for :shapes
2215
+ canvas.shapes_attributes =
2216
+ {
2217
+ "foo" => { "_type" => "Square" },
2218
+ "bar" => { "_type" => "Circle" }
2219
+ }
2220
+ end
2221
+
2222
+ it "instantiates an object of the given type" do
2223
+ expect(canvas.shapes.map(&:class)).to eq([Square, Circle])
2224
+ end
2225
+ end
2226
+ end
2227
+
2228
+ context "when the relation is a references one" do
2229
+
2230
+ let(:person) do
2231
+ Person.new
2232
+ end
2233
+
2234
+ context "when a reject proc is specified" do
2235
+
2236
+ before do
2237
+ Person.send(:undef_method, :game_attributes=)
2238
+ Person.accepts_nested_attributes_for \
2239
+ :game, reject_if: ->(attrs){ attrs[:name].blank? }
2240
+ end
2241
+
2242
+ after do
2243
+ Person.send(:undef_method, :game_attributes=)
2244
+ Person.accepts_nested_attributes_for :game
2245
+ end
2246
+
2247
+ context "when the attributes match" do
2248
+
2249
+ before do
2250
+ person.game_attributes = { score: 10 }
2251
+ end
2252
+
2253
+ it "does not add the document" do
2254
+ expect(person.game).to be_nil
2255
+ end
2256
+ end
2257
+
2258
+ context "when the attributes do not match" do
2259
+
2260
+ before do
2261
+ person.game_attributes = { name: "Tron" }
2262
+ end
2263
+
2264
+ it "adds the document" do
2265
+ expect(person.game.name).to eq("Tron")
2266
+ end
2267
+ end
2268
+ end
2269
+
2270
+ context "when reject_if => :all_blank is specified" do
2271
+
2272
+ before do
2273
+ Person.send(:undef_method, :game_attributes=)
2274
+ Person.accepts_nested_attributes_for \
2275
+ :game, reject_if: :all_blank
2276
+ end
2277
+
2278
+ after do
2279
+ Person.send(:undef_method, :game_attributes=)
2280
+ Person.accepts_nested_attributes_for :game
2281
+ end
2282
+
2283
+ context "when all attributes are empty" do
2284
+
2285
+ before do
2286
+ person.game_attributes = { score: nil }
2287
+ end
2288
+
2289
+ it "does not add the document" do
2290
+ expect(person.game).to be_nil
2291
+ end
2292
+ end
2293
+
2294
+ context "when an attribute is non-empty" do
2295
+
2296
+ before do
2297
+ person.game_attributes = { name: "Tron" }
2298
+ end
2299
+
2300
+ it "adds the document" do
2301
+ expect(person.game.name).to eq("Tron")
2302
+ end
2303
+ end
2304
+ end
2305
+
2306
+ context "when no id has been passed" do
2307
+
2308
+ context "with no destroy attribute" do
2309
+
2310
+ before do
2311
+ person.game_attributes = { name: "Tron" }
2312
+ end
2313
+
2314
+ it "builds a new document" do
2315
+ expect(person.game.name).to eq("Tron")
2316
+ end
2317
+ end
2318
+
2319
+ context "with a destroy attribute" do
2320
+
2321
+ context "when allow_destroy is true" do
2322
+
2323
+ before do
2324
+ Person.send(:undef_method, :game_attributes=)
2325
+ Person.accepts_nested_attributes_for :game, allow_destroy: true
2326
+ end
2327
+
2328
+ after do
2329
+ Person.send(:undef_method, :game_attributes=)
2330
+ Person.accepts_nested_attributes_for :game
2331
+ end
2332
+
2333
+ before do
2334
+ person.game_attributes = { name: "Tron", _destroy: "1" }
2335
+ end
2336
+
2337
+ it "does not build the document" do
2338
+ expect(person.game).to be_nil
2339
+ end
2340
+ end
2341
+
2342
+ context "when allow_destroy is false" do
2343
+
2344
+ before do
2345
+ Person.send(:undef_method, :game_attributes=)
2346
+ Person.accepts_nested_attributes_for :game, allow_destroy: false
2347
+ end
2348
+
2349
+ after do
2350
+ Person.send(:undef_method, :game_attributes=)
2351
+ Person.accepts_nested_attributes_for :game
2352
+ end
2353
+
2354
+ before do
2355
+ person.game_attributes = { name: "Tron", _destroy: "1" }
2356
+ end
2357
+
2358
+ it "builds the document" do
2359
+ expect(person.game.name).to eq("Tron")
2360
+ end
2361
+ end
2362
+ end
2363
+
2364
+ context "with empty attributes" do
2365
+
2366
+ before do
2367
+ person.game_attributes = {}
2368
+ end
2369
+
2370
+ it "does not build the document" do
2371
+ expect(person.game).to be_nil
2372
+ end
2373
+ end
2374
+
2375
+ context "when there is an existing document" do
2376
+
2377
+ context "with no destroy attribute" do
2378
+
2379
+ before do
2380
+ person.game = Game.new(name: "Tron")
2381
+ person.game_attributes = { name: "Pong" }
2382
+ end
2383
+
2384
+ it "replaces the document" do
2385
+ expect(person.game.name).to eq("Pong")
2386
+ end
2387
+ end
2388
+
2389
+ context "when updating attributes" do
2390
+
2391
+ let!(:pizza) do
2392
+ Pizza.create(name: "large")
2393
+ end
2394
+
2395
+ before do
2396
+ pizza.topping = Topping.create!(name: "cheese")
2397
+ pizza.update_attributes!(topping_attributes: { name: "onions" })
2398
+ end
2399
+
2400
+ it "persists the attribute changes" do
2401
+ expect(pizza.reload.topping.name).to eq("onions")
2402
+ end
2403
+ end
2404
+
2405
+ context "with a destroy attribute" do
2406
+
2407
+ context "when allow_destroy is true" do
2408
+
2409
+ before do
2410
+ Person.send(:undef_method, :game_attributes=)
2411
+ Person.accepts_nested_attributes_for :game, allow_destroy: true
2412
+ end
2413
+
2414
+ after do
2415
+ Person.send(:undef_method, :game_attributes=)
2416
+ Person.accepts_nested_attributes_for :game
2417
+ end
2418
+
2419
+ before do
2420
+ person.game = Game.new(name: "Tron")
2421
+ person.game_attributes = { name: "Pong", _destroy: "1" }
2422
+ end
2423
+
2424
+ it "does not replace the document" do
2425
+ expect(person.game.name).to eq("Tron")
2426
+ end
2427
+ end
2428
+
2429
+ context "when allow_destroy is false" do
2430
+
2431
+ before do
2432
+ Person.send(:undef_method, :game_attributes=)
2433
+ Person.accepts_nested_attributes_for :game, allow_destroy: false
2434
+ end
2435
+
2436
+ after do
2437
+ Person.send(:undef_method, :game_attributes=)
2438
+ Person.accepts_nested_attributes_for :game
2439
+ end
2440
+
2441
+ before do
2442
+ person.game = Game.new(name: "Tron")
2443
+ person.game_attributes = { name: "Pong", _destroy: "1" }
2444
+ end
2445
+
2446
+ it "replaces the document" do
2447
+ expect(person.game.name).to eq("Pong")
2448
+ end
2449
+ end
2450
+ end
2451
+ end
2452
+ end
2453
+
2454
+ context "when an id is passed" do
2455
+
2456
+ context "when there is an existing record" do
2457
+
2458
+ let(:game) do
2459
+ Game.new(name: "Tron")
2460
+ end
2461
+
2462
+ before do
2463
+ person.game = game
2464
+ end
2465
+
2466
+ context "when the id matches" do
2467
+
2468
+ context "when passed keys as symbols" do
2469
+
2470
+ before do
2471
+ person.game_attributes =
2472
+ { id: game.id, name: "Pong" }
2473
+ end
2474
+
2475
+ it "updates the existing document" do
2476
+ expect(person.game.name).to eq("Pong")
2477
+ end
2478
+ end
2479
+
2480
+ context "when passed keys as strings" do
2481
+
2482
+ before do
2483
+ person.game_attributes =
2484
+ { "id" => game.id, "name" => "Pong" }
2485
+ end
2486
+
2487
+ it "updates the existing document" do
2488
+ expect(person.game.name).to eq("Pong")
2489
+ end
2490
+ end
2491
+
2492
+ context "when allow_destroy is true" do
2493
+
2494
+ before do
2495
+ Person.send(:undef_method, :game_attributes=)
2496
+ Person.accepts_nested_attributes_for :game, allow_destroy: true
2497
+ end
2498
+
2499
+ after do
2500
+ Person.send(:undef_method, :game_attributes=)
2501
+ Person.accepts_nested_attributes_for :game
2502
+ end
2503
+
2504
+ [ 1, "1", true, "true" ].each do |truth|
2505
+
2506
+ context "when passed #{truth} with destroy" do
2507
+
2508
+ before do
2509
+ person.game_attributes =
2510
+ { id: game.id, _destroy: truth }
2511
+ end
2512
+
2513
+ it "destroys the existing document" do
2514
+ expect(person.game).to be_nil
2515
+ end
2516
+ end
2517
+ end
2518
+
2519
+ [ nil, 0, "0", false, "false" ].each do |falsehood|
2520
+
2521
+ context "when passed #{falsehood} with destroy" do
2522
+
2523
+ before do
2524
+ person.game_attributes =
2525
+ { id: game.id, _destroy: falsehood }
2526
+ end
2527
+
2528
+ it "does not destroy the existing document" do
2529
+ expect(person.game).to eq(game)
2530
+ end
2531
+ end
2532
+ end
2533
+ end
2534
+
2535
+ context "when allow destroy is false" do
2536
+
2537
+ before do
2538
+ Person.send(:undef_method, :game_attributes=)
2539
+ Person.accepts_nested_attributes_for :game, allow_destroy: false
2540
+ end
2541
+
2542
+ after do
2543
+ Person.send(:undef_method, :game_attributes=)
2544
+ Person.accepts_nested_attributes_for :game
2545
+ end
2546
+
2547
+ context "when a destroy attribute is passed" do
2548
+
2549
+ before do
2550
+ person.game_attributes =
2551
+ { id: game.id, _destroy: true }
2552
+ end
2553
+
2554
+ it "does not destroy the document" do
2555
+ expect(person.game).to eq(game)
2556
+ end
2557
+ end
2558
+ end
2559
+
2560
+ context "when update only is true" do
2561
+
2562
+ before do
2563
+ Person.send(:undef_method, :game_attributes=)
2564
+ Person.accepts_nested_attributes_for \
2565
+ :game,
2566
+ update_only: true,
2567
+ allow_destroy: true
2568
+ end
2569
+
2570
+ after do
2571
+ Person.send(:undef_method, :game_attributes=)
2572
+ Person.accepts_nested_attributes_for :game
2573
+ end
2574
+
2575
+ context "when the id matches" do
2576
+
2577
+ before do
2578
+ person.game_attributes =
2579
+ { id: game.id, name: "Donkey Kong" }
2580
+ end
2581
+
2582
+ it "updates the existing document" do
2583
+ expect(person.game.name).to eq("Donkey Kong")
2584
+ end
2585
+ end
2586
+
2587
+ context "when the id does not match" do
2588
+
2589
+ before do
2590
+ person.game_attributes =
2591
+ { id: BSON::ObjectId.new.to_s, name: "Pong" }
2592
+ end
2593
+
2594
+ it "updates the existing document" do
2595
+ expect(person.game.name).to eq("Pong")
2596
+ end
2597
+ end
2598
+
2599
+ context "when passed a destroy truth" do
2600
+
2601
+ before do
2602
+ person.game_attributes =
2603
+ { id: game.id, _destroy: true }
2604
+ end
2605
+
2606
+ it "destroys the existing document" do
2607
+ expect(person.game).to be_nil
2608
+ end
2609
+ end
2610
+ end
2611
+ end
2612
+ end
2613
+ end
2614
+
2615
+ context "when the nested document is invalid" do
2616
+
2617
+ before do
2618
+ Person.validates_associated(:game)
2619
+ end
2620
+
2621
+ after do
2622
+ Person.reset_callbacks(:validate)
2623
+ end
2624
+
2625
+ before do
2626
+ person.game_attributes = { name: '$$$' }
2627
+ end
2628
+
2629
+ it "propagates invalidity to parent" do
2630
+ expect(person.game).to_not be_valid
2631
+ expect(person).to_not be_valid
2632
+ end
2633
+ end
2634
+
2635
+ context "when a type is passed" do
2636
+
2637
+ let(:driver) do
2638
+ Driver.new
2639
+ end
2640
+
2641
+ before do
2642
+ Driver.send(:undef_method, :vehicle_attributes=)
2643
+ Driver.accepts_nested_attributes_for :vehicle
2644
+ driver.vehicle_attributes = { "_type" => "Truck" }
2645
+ end
2646
+
2647
+ it "instantiates an object of the given type" do
2648
+ expect(driver.vehicle.class).to eq(Truck)
2649
+ end
2650
+ end
2651
+ end
2652
+
2653
+ context "when the relation is referenced in" do
2654
+
2655
+ context "when the child is new" do
2656
+
2657
+ let(:game) do
2658
+ Game.new
2659
+ end
2660
+
2661
+ context "when no id has been passed" do
2662
+
2663
+ context "when no destroy attribute passed" do
2664
+
2665
+ before do
2666
+ game.person_attributes = { title: "Sir" }
2667
+ end
2668
+
2669
+ it "builds a new document" do
2670
+ expect(game.person.title).to eq("Sir")
2671
+ end
2672
+
2673
+ end
2674
+
2675
+ context "when a destroy attribute is passed" do
2676
+
2677
+ context "when allow_destroy is true" do
2678
+
2679
+ before do
2680
+ Game.send(:undef_method, :person_attributes=)
2681
+ Game.accepts_nested_attributes_for :person, allow_destroy: true
2682
+ end
2683
+
2684
+ after do
2685
+ Game.send(:undef_method, :person_attributes=)
2686
+ Game.accepts_nested_attributes_for :person
2687
+ end
2688
+
2689
+ before do
2690
+ game.person_attributes = { title: "Sir", _destroy: 1 }
2691
+ end
2692
+
2693
+ it "does not build a new document" do
2694
+ expect(game.person).to be_nil
2695
+ end
2696
+ end
2697
+
2698
+ context "when allow_destroy is false" do
2699
+
2700
+ before do
2701
+ Game.send(:undef_method, :person_attributes=)
2702
+ Game.accepts_nested_attributes_for :person, allow_destroy: false
2703
+ end
2704
+
2705
+ after do
2706
+ Game.send(:undef_method, :person_attributes=)
2707
+ Game.accepts_nested_attributes_for :person
2708
+ end
2709
+
2710
+ before do
2711
+ game.person_attributes = { title: "Sir", _destroy: 1 }
2712
+ end
2713
+
2714
+ it "builds a new document" do
2715
+ expect(game.person.title).to eq("Sir")
2716
+ end
2717
+ end
2718
+ end
2719
+ end
2720
+
2721
+ context "when an id has been passed" do
2722
+
2723
+ let(:person) do
2724
+ Person.new
2725
+ end
2726
+
2727
+ context "when no destroy attribute passed" do
2728
+
2729
+ context "when the id matches" do
2730
+
2731
+ before do
2732
+ game.person_attributes = { id: person.id, title: "Sir" }
2733
+ end
2734
+
2735
+ it "updates the existing document" do
2736
+ expect(game.person.title).to eq("Sir")
2737
+ end
2738
+ end
2739
+ end
2740
+
2741
+ context "when there is an existing document" do
2742
+
2743
+ before do
2744
+ game.person = person
2745
+ end
2746
+
2747
+ context "when allow destroy is true" do
2748
+
2749
+ before do
2750
+ Game.send(:undef_method, :person_attributes=)
2751
+ Game.accepts_nested_attributes_for :person, allow_destroy: true
2752
+ end
2753
+
2754
+ after do
2755
+ Game.send(:undef_method, :person_attributes=)
2756
+ Game.accepts_nested_attributes_for :person
2757
+ end
2758
+
2759
+ [ 1, "1", true, "true" ].each do |truth|
2760
+
2761
+ context "when passed #{truth} with destroy" do
2762
+
2763
+ before do
2764
+ game.person_attributes =
2765
+ { id: person.id, _destroy: truth }
2766
+ end
2767
+
2768
+ it "destroys the existing document" do
2769
+ expect(game.person).to be_nil
2770
+ end
2771
+ end
2772
+ end
2773
+
2774
+ [ nil, 0, "0", false, "false" ].each do |falsehood|
2775
+
2776
+ context "when passed #{falsehood} with destroy" do
2777
+
2778
+ before do
2779
+ game.person_attributes =
2780
+ { id: person.id, _destroy: falsehood }
2781
+ end
2782
+
2783
+ it "does not destroy the existing document" do
2784
+ expect(game.person).to eq(person)
2785
+ end
2786
+ end
2787
+ end
2788
+ end
2789
+
2790
+ context "when allow destroy is false" do
2791
+
2792
+ before do
2793
+ Game.send(:undef_method, :person_attributes=)
2794
+ Game.accepts_nested_attributes_for :person, allow_destroy: false
2795
+ end
2796
+
2797
+ after do
2798
+ Game.send(:undef_method, :person_attributes=)
2799
+ Game.accepts_nested_attributes_for :person
2800
+ end
2801
+
2802
+ context "when a destroy attribute is passed" do
2803
+
2804
+ before do
2805
+ game.person_attributes =
2806
+ { id: person.id, _destroy: true }
2807
+ end
2808
+
2809
+ it "does not delete the document" do
2810
+ expect(game.person).to eq(person)
2811
+ end
2812
+ end
2813
+ end
2814
+
2815
+ context "when update only is true" do
2816
+
2817
+ before do
2818
+ Game.send(:undef_method, :person_attributes=)
2819
+ Game.accepts_nested_attributes_for \
2820
+ :person,
2821
+ update_only: true,
2822
+ allow_destroy: true
2823
+ end
2824
+
2825
+ context "when the id matches" do
2826
+
2827
+ before do
2828
+ game.person_attributes =
2829
+ { id: person.id, title: "Madam" }
2830
+ end
2831
+
2832
+ it "updates the existing document" do
2833
+ expect(game.person.title).to eq("Madam")
2834
+ end
2835
+ end
2836
+
2837
+ context "when the id does not match" do
2838
+
2839
+ before do
2840
+ game.person_attributes =
2841
+ { id: BSON::ObjectId.new.to_s, title: "Madam" }
2842
+ end
2843
+
2844
+ it "updates the existing document" do
2845
+ expect(game.person.title).to eq("Madam")
2846
+ end
2847
+ end
2848
+
2849
+ context "when passed a destroy truth" do
2850
+
2851
+ before do
2852
+ game.person_attributes =
2853
+ { id: person.id, title: "Madam", _destroy: "true" }
2854
+ end
2855
+
2856
+ it "deletes the existing document" do
2857
+ expect(game.person).to be_nil
2858
+ end
2859
+ end
2860
+ end
2861
+ end
2862
+ end
2863
+
2864
+ context "when the nested document is invalid" do
2865
+
2866
+ before do
2867
+ Person.validates_format_of :ssn, without: /\$\$\$/
2868
+ end
2869
+
2870
+ after do
2871
+ Person.reset_callbacks(:validate)
2872
+ end
2873
+
2874
+ before do
2875
+ game.person_attributes = { ssn: '$$$' }
2876
+ end
2877
+
2878
+ it "propagates invalidity to parent" do
2879
+ expect(game.person).to_not be_valid
2880
+ expect(game).to_not be_valid
2881
+ end
2882
+ end
2883
+ end
2884
+
2885
+ context "when a type is passed" do
2886
+
2887
+ let(:vehicle) do
2888
+ Vehicle.new
2889
+ end
2890
+
2891
+ before do
2892
+ Vehicle.send(:undef_method, :driver_attributes=)
2893
+ Vehicle.accepts_nested_attributes_for :driver
2894
+ vehicle.driver_attributes = { "_type" => "Learner" }
2895
+ end
2896
+
2897
+ it "instantiates an object of the given type" do
2898
+ expect(vehicle.driver.class).to eq(Learner)
2899
+ end
2900
+ end
2901
+ end
2902
+
2903
+ context "when the relation is a references many" do
2904
+
2905
+ let(:person) do
2906
+ Person.new
2907
+ end
2908
+
2909
+ let(:post_one) do
2910
+ Post.new(title: "First post")
2911
+ end
2912
+
2913
+ let(:post_two) do
2914
+ Post.new(title: "First response")
2915
+ end
2916
+
2917
+ context "when a limit is specified" do
2918
+
2919
+ before do
2920
+ Person.send(:undef_method, :posts_attributes=)
2921
+ Person.accepts_nested_attributes_for :posts, limit: 2
2922
+ end
2923
+
2924
+ after do
2925
+ Person.send(:undef_method, :posts_attributes=)
2926
+ Person.accepts_nested_attributes_for :posts
2927
+ end
2928
+
2929
+ context "when more are provided than the limit" do
2930
+
2931
+ let(:attributes) do
2932
+ {
2933
+ "foo" => { "title" => "First" },
2934
+ "bar" => { "title" => "Second" },
2935
+ "baz" => { "title" => "Third" }
2936
+ }
2937
+ end
2938
+
2939
+ it "raises an error" do
2940
+ expect {
2941
+ person.posts_attributes = attributes
2942
+ }.to raise_error(Mongoid::Errors::TooManyNestedAttributeRecords)
2943
+ end
2944
+ end
2945
+
2946
+ context "when less are provided than the limit" do
2947
+
2948
+ let(:attributes) do
2949
+ {
2950
+ "foo" => { "title" => "First" },
2951
+ "bar" => { "title" => "Second" }
2952
+ }
2953
+ end
2954
+
2955
+ before do
2956
+ person.posts_attributes = attributes
2957
+ end
2958
+
2959
+ it "sets the documents on the relation" do
2960
+ expect(person.posts.size).to eq(2)
2961
+ end
2962
+
2963
+ it "does not persist the new documents" do
2964
+ expect(person.posts.count).to eq(0)
2965
+ end
2966
+ end
2967
+ end
2968
+
2969
+ context "when ids are passed" do
2970
+
2971
+ let(:person) do
2972
+ Person.create!
2973
+ end
2974
+
2975
+ before do
2976
+ person.posts << [ post_one, post_two ]
2977
+ end
2978
+
2979
+ context "when no destroy attributes are passed" do
2980
+
2981
+ context "when the ids match" do
2982
+
2983
+ before do
2984
+ person.posts_attributes =
2985
+ {
2986
+ "0" => { "id" => post_one.id, "title" => "First" },
2987
+ "1" => { "id" => post_two.id, "title" => "Second" }
2988
+ }
2989
+ end
2990
+
2991
+ context "when reloading the document" do
2992
+
2993
+ it "updates the first existing document" do
2994
+ expect(person.posts(true)[0].title).to eq("First")
2995
+ end
2996
+
2997
+ it "updates the second existing document" do
2998
+ expect(person.posts(true)[1].title).to eq("Second")
2999
+ end
3000
+
3001
+ it "does not add new documents" do
3002
+ expect(person.posts(true).size).to eq(2)
3003
+ end
3004
+ end
3005
+
3006
+ context "when there are no documents" do
3007
+
3008
+ before do
3009
+ person.posts.clear
3010
+ end
3011
+
3012
+ it "raises a document not found error" do
3013
+ expect {
3014
+ person.posts_attributes =
3015
+ { "0" =>
3016
+ { "id" => BSON::ObjectId.new.to_s, "title" => "Rogue" }
3017
+ }
3018
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Post with id\(s\)/)
3019
+ end
3020
+ end
3021
+ end
3022
+
3023
+ context "when the parent is freshly loaded from the db" do
3024
+
3025
+ before do
3026
+ person.reload
3027
+ end
3028
+
3029
+ context "when updating valid documents with invalid values" do
3030
+
3031
+ before do
3032
+ person.posts_attributes =
3033
+ {
3034
+ "0" => { "id" => post_one.id, "title" => "testing again" },
3035
+ "1" => { "id" => post_two.id, "title" => "$$$" }
3036
+ }
3037
+ person.save!
3038
+ end
3039
+
3040
+ it "does not perist the invalid value" do
3041
+ expect(post_two.reload.title).to eq("First response")
3042
+ end
3043
+ end
3044
+ end
3045
+
3046
+ context "when the ids do not match" do
3047
+
3048
+ it "raises an error" do
3049
+ expect {
3050
+ person.posts_attributes =
3051
+ { "foo" => { "id" => "test", "title" => "Test" } }
3052
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Post with id\(s\)/)
3053
+ end
3054
+ end
3055
+ end
3056
+
3057
+ context "when destroy attributes are passed" do
3058
+
3059
+ context "when the ids match" do
3060
+
3061
+ context "when allow_destroy is true" do
3062
+
3063
+ before do
3064
+ Person.send(:undef_method, :posts_attributes=)
3065
+ Person.accepts_nested_attributes_for :posts, allow_destroy: true
3066
+ end
3067
+
3068
+ after do
3069
+ Person.send(:undef_method, :posts_attributes=)
3070
+ Person.accepts_nested_attributes_for :posts
3071
+ end
3072
+
3073
+ [ 1, "1", true, "true" ].each do |truth|
3074
+
3075
+ context "when passed a #{truth} with destroy" do
3076
+
3077
+ before do
3078
+ person.posts_attributes =
3079
+ {
3080
+ "0" => { "id" => post_one.id, "_destroy" => truth },
3081
+ "1" => { "id" => post_two.id, "title" => "My Blog" }
3082
+ }
3083
+ end
3084
+
3085
+ context "when reloading the documents" do
3086
+
3087
+ it "deletes the marked document" do
3088
+ expect(person.posts(true).size).to eq(1)
3089
+ end
3090
+
3091
+ it "does not delete the unmarked document" do
3092
+ expect(person.posts(true).first.title).to eq("My Blog")
3093
+ end
3094
+ end
3095
+ end
3096
+ end
3097
+
3098
+ [ 0, "0", false, "false" ].each do |falsehood|
3099
+
3100
+ context "when passed a #{falsehood} with destroy" do
3101
+
3102
+ before do
3103
+ person.posts_attributes =
3104
+ {
3105
+ "0" => { "id" => post_one.id, "_destroy" => falsehood },
3106
+ "1" => { "id" => post_two.id, "title" => "My Blog" }
3107
+ }
3108
+ end
3109
+
3110
+ context "when reloading the document" do
3111
+
3112
+ it "does not delete the marked document" do
3113
+ expect(person.posts(true).size).to eq(2)
3114
+ end
3115
+
3116
+ it "does not delete the unmarked document" do
3117
+ expect(person.posts(true).map(&:title)).to include("My Blog")
3118
+ end
3119
+ end
3120
+ end
3121
+ end
3122
+ end
3123
+
3124
+ context "when allow_destroy is false" do
3125
+
3126
+ before do
3127
+ Person.send(:undef_method, :posts_attributes=)
3128
+ Person.accepts_nested_attributes_for :posts, allow_destroy: false
3129
+ end
3130
+
3131
+ after do
3132
+ Person.send(:undef_method, :posts_attributes=)
3133
+ Person.accepts_nested_attributes_for :posts
3134
+ end
3135
+
3136
+ [ 1, "1", true, "true" ].each do |truth|
3137
+
3138
+ context "when passed a #{truth} with destroy" do
3139
+
3140
+ before do
3141
+ person.posts_attributes =
3142
+ {
3143
+ "0" => {
3144
+ "id" => post_one.id, "title" => "Another Title", "_destroy" => truth },
3145
+ "1" => { "id" => post_two.id, "title" => "New Title" }
3146
+ }
3147
+ end
3148
+
3149
+ context "when reloading the document" do
3150
+
3151
+ it "does not ignore the marked document" do
3152
+ expect(person.posts(true)[0].title).to eq("Another Title")
3153
+ end
3154
+
3155
+ it "does not delete the unmarked document" do
3156
+ expect(person.posts(true)[1].title).to eq("New Title")
3157
+ end
3158
+
3159
+ it "does not add additional documents" do
3160
+ expect(person.posts(true).size).to eq(2)
3161
+ end
3162
+ end
3163
+ end
3164
+ end
3165
+
3166
+ [ 0, "0", false, "false" ].each do |falsehood|
3167
+
3168
+ context "when passed a #{falsehood} with destroy" do
3169
+
3170
+ before do
3171
+ person.posts_attributes =
3172
+ {
3173
+ "0" => { "id" => post_one.id, "_destroy" => falsehood },
3174
+ "1" => { "id" => post_two.id, "title" => "New Title" }
3175
+ }
3176
+ end
3177
+
3178
+ context "when reloading the documents" do
3179
+
3180
+ it "does not delete the marked document" do
3181
+ expect(person.posts(true).size).to eq(2)
3182
+ end
3183
+
3184
+ it "does not delete the unmarked document" do
3185
+ expect(person.posts(true)[1].title).to eq("New Title")
3186
+ end
3187
+ end
3188
+ end
3189
+ end
3190
+ end
3191
+
3192
+ context "when allow_destroy is undefined" do
3193
+
3194
+ before do
3195
+ Person.send(:undef_method, :posts_attributes=)
3196
+ Person.accepts_nested_attributes_for :posts
3197
+ end
3198
+
3199
+ after do
3200
+ Person.send(:undef_method, :posts_attributes=)
3201
+ Person.accepts_nested_attributes_for :posts
3202
+ end
3203
+
3204
+ [ 1, "1", true, "true" ].each do |truth|
3205
+
3206
+ context "when passed a #{truth} with destroy" do
3207
+
3208
+ before do
3209
+ person.posts_attributes =
3210
+ {
3211
+ "0" => {
3212
+ "id" => post_one.id,
3213
+ "title" => "Another Title",
3214
+ "_destroy" => truth
3215
+ },
3216
+ "1" => { "id" => post_two.id, "title" => "New Title" }
3217
+ }
3218
+ end
3219
+
3220
+ context "when reloading" do
3221
+
3222
+ it "does not ignore the marked document" do
3223
+ expect(person.posts(true).find(post_one.id).title).to eq("Another Title")
3224
+ end
3225
+
3226
+ it "does not delete the unmarked document" do
3227
+ expect(person.posts(true).find(post_two.id).title).to eq("New Title")
3228
+ end
3229
+
3230
+ it "does not add additional documents" do
3231
+ expect(person.posts(true).size).to eq(2)
3232
+ end
3233
+ end
3234
+ end
3235
+ end
3236
+
3237
+ [ 0, "0", false, "false" ].each do |falsehood|
3238
+
3239
+ context "when passed a #{falsehood} with destroy" do
3240
+
3241
+ before do
3242
+ person.posts_attributes =
3243
+ {
3244
+ "0" => { "id" => post_one.id, "_destroy" => falsehood },
3245
+ "1" => { "id" => post_two.id, "title" => "New Title" }
3246
+ }
3247
+ end
3248
+
3249
+ context "when reloading" do
3250
+
3251
+ it "does not delete the marked document" do
3252
+ expect(person.posts(true).size).to eq(2)
3253
+ end
3254
+
3255
+ it "does not delete the unmarked document" do
3256
+ expect(person.posts(true)[1].title).to eq("New Title")
3257
+ end
3258
+ end
3259
+ end
3260
+ end
3261
+ end
3262
+ end
3263
+ end
3264
+ end
3265
+
3266
+ context "when no ids are passed" do
3267
+
3268
+ context "when no destroy attributes are passed" do
3269
+
3270
+ context "when passing a hash of attributes" do
3271
+
3272
+ before do
3273
+ person.posts_attributes =
3274
+ {
3275
+ "4" => { "title" => "Third" },
3276
+ "1" => { "title" => "First" },
3277
+ "2" => { "title" => "Second" }
3278
+ }
3279
+ end
3280
+
3281
+ it "builds a new first document" do
3282
+ expect(person.posts[0].title).to eq("First")
3283
+ end
3284
+
3285
+ it "builds a new second document" do
3286
+ expect(person.posts[1].title).to eq("Second")
3287
+ end
3288
+
3289
+ it "builds a new third document" do
3290
+ expect(person.posts[2].title).to eq("Third")
3291
+ end
3292
+
3293
+ it "does not add extra documents" do
3294
+ expect(person.posts.size).to eq(3)
3295
+ end
3296
+
3297
+ it "does not persist the documents" do
3298
+ expect(person.posts.count).to eq(0)
3299
+ end
3300
+
3301
+ it "adds the documents in the sorted hash key order" do
3302
+ expect(person.posts.map(&:title)).to eq(
3303
+ [ "First", "Second", "Third" ]
3304
+ )
3305
+ end
3306
+ end
3307
+
3308
+ context "when passing an array of attributes" do
3309
+
3310
+ context "when the parent is saved" do
3311
+
3312
+ before do
3313
+ person.save!
3314
+ person.posts_attributes =
3315
+ [
3316
+ { "title" => "Third" },
3317
+ { "title" => "First" },
3318
+ { "title" => "Second" }
3319
+ ]
3320
+ end
3321
+
3322
+ it "builds a new first document" do
3323
+ expect(person.posts.first.title).to eq("Third")
3324
+ end
3325
+
3326
+ it "builds a new second document" do
3327
+ expect(person.posts.second.title).to eq("First")
3328
+ end
3329
+
3330
+ it "builds a new third document" do
3331
+ expect(person.posts.third.title).to eq("Second")
3332
+ end
3333
+
3334
+ it "does not add extra documents" do
3335
+ expect(person.posts.size).to eq(3)
3336
+ end
3337
+
3338
+ it "does not persist the documents" do
3339
+ expect(person.posts.count).to eq(0)
3340
+ end
3341
+ end
3342
+ end
3343
+ end
3344
+
3345
+ context "when a reject block is supplied" do
3346
+
3347
+ before do
3348
+ Person.send(:undef_method, :posts_attributes=)
3349
+ Person.accepts_nested_attributes_for \
3350
+ :posts, reject_if: ->(attrs){ attrs["title"].blank? }
3351
+ end
3352
+
3353
+ after do
3354
+ Person.send(:undef_method, :posts_attributes=)
3355
+ Person.accepts_nested_attributes_for :posts
3356
+ end
3357
+
3358
+ context "when the attributes match" do
3359
+
3360
+ before do
3361
+ person.posts_attributes =
3362
+ { "3" => { "content" => "My first blog" } }
3363
+ end
3364
+
3365
+ it "does not add the new document" do
3366
+ expect(person.posts).to be_empty
3367
+ end
3368
+ end
3369
+
3370
+ context "when the attributes do not match" do
3371
+
3372
+ before do
3373
+ person.posts_attributes =
3374
+ { "3" => { "title" => "Blogging" } }
3375
+ end
3376
+
3377
+ it "adds the new document" do
3378
+ expect(person.posts.size).to eq(1)
3379
+ end
3380
+
3381
+ it "sets the correct attributes" do
3382
+ expect(person.posts.first.title).to eq("Blogging")
3383
+ end
3384
+ end
3385
+ end
3386
+
3387
+ context "when :reject_if => :all_blank is supplied" do
3388
+
3389
+ before do
3390
+ Person.send(:undef_method, :posts_attributes=)
3391
+ Person.accepts_nested_attributes_for \
3392
+ :posts, reject_if: :all_blank
3393
+ end
3394
+
3395
+ after do
3396
+ Person.send(:undef_method, :posts_attributes=)
3397
+ Person.accepts_nested_attributes_for :posts
3398
+ end
3399
+
3400
+ context "when all attributes are blank" do
3401
+
3402
+ before do
3403
+ person.posts_attributes =
3404
+ { "3" => { "content" => "" } }
3405
+ end
3406
+
3407
+ it "does not add the new document" do
3408
+ expect(person.posts).to be_empty
3409
+ end
3410
+ end
3411
+
3412
+ context "when an attribute is non-empty" do
3413
+
3414
+ before do
3415
+ person.posts_attributes =
3416
+ { "3" => { "title" => "Blogging" } }
3417
+ end
3418
+
3419
+ it "adds the new document" do
3420
+ expect(person.posts.size).to eq(1)
3421
+ end
3422
+
3423
+ it "sets the correct attributes" do
3424
+ expect(person.posts.first.title).to eq("Blogging")
3425
+ end
3426
+ end
3427
+ end
3428
+
3429
+ context "when destroy attributes are passed" do
3430
+
3431
+ context "when allow_destroy is true" do
3432
+
3433
+ before do
3434
+ Person.send(:undef_method, :posts_attributes=)
3435
+ Person.accepts_nested_attributes_for :posts, allow_destroy: true
3436
+ end
3437
+
3438
+ after do
3439
+ Person.send(:undef_method, :posts_attributes=)
3440
+ Person.accepts_nested_attributes_for :posts
3441
+ end
3442
+
3443
+ [ 1, "1", true, "true" ].each do |truth|
3444
+
3445
+ context "when passed a #{truth} with destroy" do
3446
+
3447
+ before do
3448
+ person.posts_attributes =
3449
+ {
3450
+ "0" => { "title" => "New Blog", "_destroy" => truth },
3451
+ "1" => { "title" => "Blog Two" }
3452
+ }
3453
+ end
3454
+
3455
+ it "ignores the marked document" do
3456
+ expect(person.posts.size).to eq(1)
3457
+ end
3458
+
3459
+ it "adds the new unmarked document" do
3460
+ expect(person.posts.first.title).to eq("Blog Two")
3461
+ end
3462
+ end
3463
+ end
3464
+
3465
+ [ 0, "0", false, "false" ].each do |falsehood|
3466
+
3467
+ context "when passed a #{falsehood} with destroy" do
3468
+
3469
+ before do
3470
+ person.posts_attributes =
3471
+ {
3472
+ "0" => { "title" => "New Blog", "_destroy" => falsehood },
3473
+ "1" => { "title" => "Blog Two" }
3474
+ }
3475
+ end
3476
+
3477
+ it "adds the new marked document" do
3478
+ expect(person.posts.first.title).to eq("New Blog")
3479
+ end
3480
+
3481
+ it "adds the new unmarked document" do
3482
+ expect(person.posts.last.title).to eq("Blog Two")
3483
+ end
3484
+
3485
+ it "does not add extra documents" do
3486
+ expect(person.posts.size).to eq(2)
3487
+ end
3488
+ end
3489
+ end
3490
+ end
3491
+
3492
+ context "when allow destroy is false" do
3493
+
3494
+ before do
3495
+ Person.send(:undef_method, :posts_attributes=)
3496
+ Person.accepts_nested_attributes_for :posts, allow_destroy: false
3497
+ end
3498
+
3499
+ after do
3500
+ Person.send(:undef_method, :posts_attributes=)
3501
+ Person.accepts_nested_attributes_for :posts
3502
+ end
3503
+
3504
+ [ 1, "1", true, "true" ].each do |truth|
3505
+
3506
+ context "when passed a #{truth} with destroy" do
3507
+
3508
+ before do
3509
+ person.posts_attributes =
3510
+ {
3511
+ "0" => { "title" => "New Blog", "_destroy" => truth },
3512
+ "1" => { "title" => "Blog Two" }
3513
+ }
3514
+ end
3515
+
3516
+ it "adds the marked document" do
3517
+ expect(person.posts.first.title).to eq("New Blog")
3518
+ end
3519
+
3520
+ it "adds the new unmarked document" do
3521
+ expect(person.posts.last.title).to eq("Blog Two")
3522
+ end
3523
+
3524
+ it "adds the correct number of documents" do
3525
+ expect(person.posts.size).to eq(2)
3526
+ end
3527
+ end
3528
+ end
3529
+
3530
+ [ 0, "0", false, "false" ].each do |falsehood|
3531
+
3532
+ context "when passed a #{falsehood} with destroy" do
3533
+
3534
+ before do
3535
+ person.posts_attributes =
3536
+ {
3537
+ "0" => { "title" => "New Blog", "_destroy" => falsehood },
3538
+ "1" => { "title" => "Blog Two" }
3539
+ }
3540
+ end
3541
+
3542
+ it "adds the new marked document" do
3543
+ expect(person.posts.first.title).to eq("New Blog")
3544
+ end
3545
+
3546
+ it "adds the new unmarked document" do
3547
+ expect(person.posts.last.title).to eq("Blog Two")
3548
+ end
3549
+
3550
+ it "does not add extra documents" do
3551
+ expect(person.posts.size).to eq(2)
3552
+ end
3553
+ end
3554
+ end
3555
+ end
3556
+
3557
+ context "when allow destroy is not defined" do
3558
+
3559
+ before do
3560
+ Person.send(:undef_method, :posts_attributes=)
3561
+ Person.accepts_nested_attributes_for :posts
3562
+ end
3563
+
3564
+ [ 1, "1", true, "true" ].each do |truth|
3565
+
3566
+ context "when passed a #{truth} with destroy" do
3567
+
3568
+ before do
3569
+ person.posts_attributes =
3570
+ {
3571
+ "0" => { "title" => "New Blog", "_destroy" => truth },
3572
+ "1" => { "title" => "Blog Two" }
3573
+ }
3574
+ end
3575
+
3576
+ it "adds the marked document" do
3577
+ expect(person.posts.first.title).to eq("New Blog")
3578
+ end
3579
+
3580
+ it "adds the new unmarked document" do
3581
+ expect(person.posts.last.title).to eq("Blog Two")
3582
+ end
3583
+
3584
+ it "adds the correct number of documents" do
3585
+ expect(person.posts.size).to eq(2)
3586
+ end
3587
+ end
3588
+ end
3589
+
3590
+ [ 0, "0", false, "false" ].each do |falsehood|
3591
+
3592
+ context "when passed a #{falsehood} with destroy" do
3593
+
3594
+ before do
3595
+ person.posts_attributes =
3596
+ {
3597
+ "0" => { "title" => "New Blog", "_destroy" => falsehood },
3598
+ "1" => { "title" => "Blog Two" }
3599
+ }
3600
+ end
3601
+
3602
+ it "adds the new marked document" do
3603
+ expect(person.posts.first.title).to eq("New Blog")
3604
+ end
3605
+
3606
+ it "adds the new unmarked document" do
3607
+ expect(person.posts.last.title).to eq("Blog Two")
3608
+ end
3609
+
3610
+ it "does not add extra documents" do
3611
+ expect(person.posts.size).to eq(2)
3612
+ end
3613
+ end
3614
+ end
3615
+ end
3616
+ end
3617
+ end
3618
+
3619
+ context "when the nested document is invalid" do
3620
+
3621
+ before do
3622
+ Person.validates_associated(:posts)
3623
+ end
3624
+
3625
+ after do
3626
+ Person.reset_callbacks(:validate)
3627
+ end
3628
+
3629
+ before do
3630
+ person.posts_attributes = {
3631
+ "0" => { title: "$$$" }
3632
+ }
3633
+ end
3634
+
3635
+ it "propagates invalidity to parent" do
3636
+ expect(person).to_not be_valid
3637
+ expect(person.posts.first).to_not be_valid
3638
+ end
3639
+ end
3640
+
3641
+ context "when a type is passed" do
3642
+
3643
+ let(:shipping_container) do
3644
+ ShippingContainer.new
3645
+ end
3646
+
3647
+ before do
3648
+ ShippingContainer.send(:undef_method, :vehicles_attributes=)
3649
+ ShippingContainer.accepts_nested_attributes_for :vehicles
3650
+ shipping_container.vehicles_attributes =
3651
+ {
3652
+ "foo" => { "_type" => "Car" },
3653
+ "bar" => { "_type" => "Truck" }
3654
+ }
3655
+ end
3656
+
3657
+ it "instantiates an object of the given type" do
3658
+ expect(shipping_container.vehicles.map(&:class)).to eq([Car, Truck])
3659
+ end
3660
+ end
3661
+ end
3662
+
3663
+ context "when the relation is a references many to many" do
3664
+
3665
+ let(:person) do
3666
+ Person.new
3667
+ end
3668
+
3669
+ let(:preference_one) do
3670
+ Preference.new(name: "First preference")
3671
+ end
3672
+
3673
+ let(:preference_two) do
3674
+ Preference.new(name: "First response")
3675
+ end
3676
+
3677
+ context "when a limit is specified" do
3678
+
3679
+ before do
3680
+ Person.send(:undef_method, :preferences_attributes=)
3681
+ Person.accepts_nested_attributes_for :preferences, limit: 2
3682
+ end
3683
+
3684
+ after do
3685
+ Person.send(:undef_method, :preferences_attributes=)
3686
+ Person.accepts_nested_attributes_for :preferences
3687
+ end
3688
+
3689
+ context "when more are provided than the limit" do
3690
+
3691
+ let(:attributes) do
3692
+ {
3693
+ "foo" => { "name" => "First" },
3694
+ "bar" => { "name" => "Second" },
3695
+ "baz" => { "name" => "Third" }
3696
+ }
3697
+ end
3698
+
3699
+ it "raises an error" do
3700
+ expect {
3701
+ person.preferences_attributes = attributes
3702
+ }.to raise_error(Mongoid::Errors::TooManyNestedAttributeRecords)
3703
+ end
3704
+ end
3705
+
3706
+ context "when less are provided than the limit" do
3707
+
3708
+ let(:attributes) do
3709
+ {
3710
+ "foo" => { "name" => "First" },
3711
+ "bar" => { "name" => "Second" }
3712
+ }
3713
+ end
3714
+
3715
+ before do
3716
+ person.preferences_attributes = attributes
3717
+ end
3718
+
3719
+ it "sets the documents on the relation" do
3720
+ expect(person.preferences.size).to eq(2)
3721
+ end
3722
+ end
3723
+ end
3724
+
3725
+ context "when ids are passed" do
3726
+
3727
+ let(:person) do
3728
+ Person.create!
3729
+ end
3730
+
3731
+ before do
3732
+ person.preferences << [ preference_one, preference_two ]
3733
+ end
3734
+
3735
+ context "when no destroy attributes are passed" do
3736
+
3737
+ context "when the ids match" do
3738
+
3739
+ before do
3740
+ person.preferences_attributes =
3741
+ {
3742
+ "0" => { "id" => preference_one.id, "name" => "First" },
3743
+ "1" => { "id" => preference_two.id, "name" => "Second" }
3744
+ }
3745
+ end
3746
+
3747
+ context "when reloading the document" do
3748
+
3749
+ it "updates the first existing document" do
3750
+ expect(person.preferences(true).first.name).to eq("First")
3751
+ end
3752
+
3753
+ it "updates the second existing document" do
3754
+ expect(person.preferences(true).second.name).to eq("Second")
3755
+ end
3756
+
3757
+ it "does not add new documents" do
3758
+ expect(person.preferences(true).size).to eq(2)
3759
+ end
3760
+ end
3761
+ end
3762
+
3763
+ context "when the ids do not match" do
3764
+
3765
+ it "raises an error" do
3766
+ expect {
3767
+ person.preferences_attributes =
3768
+ { "foo" => { "id" => "test", "name" => "Test" } }
3769
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Preference with id\(s\)/)
3770
+ end
3771
+ end
3772
+ end
3773
+
3774
+ context "when destroy attributes are passed" do
3775
+
3776
+ context "when the ids match" do
3777
+
3778
+ context "when allow_destroy is true" do
3779
+
3780
+ before do
3781
+ Person.send(:undef_method, :preferences_attributes=)
3782
+ Person.accepts_nested_attributes_for :preferences, allow_destroy: true
3783
+ end
3784
+
3785
+ after do
3786
+ Person.send(:undef_method, :preferences_attributes=)
3787
+ Person.accepts_nested_attributes_for :preferences
3788
+ end
3789
+
3790
+ [ 1, "1", true, "true" ].each do |truth|
3791
+
3792
+ context "when passed a #{truth} with destroy" do
3793
+
3794
+ before do
3795
+ person.preferences_attributes =
3796
+ {
3797
+ "0" => { "id" => preference_one.id, "_destroy" => truth },
3798
+ "1" => { "id" => preference_two.id, "name" => "My Blog" }
3799
+ }
3800
+ end
3801
+
3802
+ context "when reloading the documents" do
3803
+
3804
+ it "deletes the marked document" do
3805
+ expect(person.preferences(true).size).to eq(1)
3806
+ end
3807
+
3808
+ it "does not delete the unmarked document" do
3809
+ expect(person.preferences(true).first.name).to eq("My Blog")
3810
+ end
3811
+ end
3812
+ end
3813
+ end
3814
+
3815
+ [ 0, "0", false, "false" ].each do |falsehood|
3816
+
3817
+ context "when passed a #{falsehood} with destroy" do
3818
+
3819
+ before do
3820
+ person.preferences_attributes =
3821
+ {
3822
+ "0" => { "id" => preference_one.id, "_destroy" => falsehood },
3823
+ "1" => { "id" => preference_two.id, "name" => "My Blog" }
3824
+ }
3825
+ end
3826
+
3827
+ context "when reloading the document" do
3828
+
3829
+ it "does not delete the marked document" do
3830
+ expect(person.preferences(true).size).to eq(2)
3831
+ end
3832
+
3833
+ it "does not delete the unmarked document" do
3834
+ expect(person.preferences(true)[1].name).to eq("My Blog")
3835
+ end
3836
+ end
3837
+ end
3838
+ end
3839
+ end
3840
+
3841
+ context "when allow_destroy is false" do
3842
+
3843
+ before do
3844
+ Person.send(:undef_method, :preferences_attributes=)
3845
+ Person.accepts_nested_attributes_for :preferences, allow_destroy: false
3846
+ end
3847
+
3848
+ after do
3849
+ Person.send(:undef_method, :preferences_attributes=)
3850
+ Person.accepts_nested_attributes_for :preferences
3851
+ end
3852
+
3853
+ [ 1, "1", true, "true" ].each do |truth|
3854
+
3855
+ context "when passed a #{truth} with destroy" do
3856
+
3857
+ before do
3858
+ person.preferences_attributes =
3859
+ {
3860
+ "0" => {
3861
+ "id" => preference_one.id, "name" => "Another Title", "_destroy" => truth },
3862
+ "1" => { "id" => preference_two.id, "name" => "New Title" }
3863
+ }
3864
+ end
3865
+
3866
+ context "when reloading the document" do
3867
+
3868
+ it "does not ignore the marked document" do
3869
+ expect(person.preferences(true)[0].name).to eq("Another Title")
3870
+ end
3871
+
3872
+ it "does not delete the unmarked document" do
3873
+ expect(person.preferences(true)[1].name).to eq("New Title")
3874
+ end
3875
+
3876
+ it "does not add additional documents" do
3877
+ expect(person.preferences(true).size).to eq(2)
3878
+ end
3879
+ end
3880
+ end
3881
+ end
3882
+
3883
+ [ 0, "0", false, "false" ].each do |falsehood|
3884
+
3885
+ context "when passed a #{falsehood} with destroy" do
3886
+
3887
+ before do
3888
+ person.preferences_attributes =
3889
+ {
3890
+ "0" => { "id" => preference_one.id, "_destroy" => falsehood },
3891
+ "1" => { "id" => preference_two.id, "name" => "New Title" }
3892
+ }
3893
+ end
3894
+
3895
+ context "when reloading the documents" do
3896
+
3897
+ it "does not delete the marked document" do
3898
+ expect(person.preferences(true).size).to eq(2)
3899
+ end
3900
+
3901
+ it "does not delete the unmarked document" do
3902
+ expect(person.preferences(true)[1].name).to eq("New Title")
3903
+ end
3904
+ end
3905
+ end
3906
+ end
3907
+ end
3908
+
3909
+ context "when allow_destroy is undefined" do
3910
+
3911
+ before do
3912
+ Person.send(:undef_method, :preferences_attributes=)
3913
+ Person.accepts_nested_attributes_for :preferences
3914
+ end
3915
+
3916
+ [ 1, "1", true, "true" ].each do |truth|
3917
+
3918
+ context "when passed a #{truth} with destroy" do
3919
+
3920
+ before do
3921
+ person.preferences_attributes =
3922
+ {
3923
+ "0" => {
3924
+ "id" => preference_one.id, "name" => "Another Title", "_destroy" => truth },
3925
+ "1" => { "id" => preference_two.id, "name" => "New Title" }
3926
+ }
3927
+ end
3928
+
3929
+ context "when reloading" do
3930
+
3931
+ it "does not ignore the marked document" do
3932
+ expect(person.preferences(true)[0].name).to eq("Another Title")
3933
+ end
3934
+
3935
+ it "does not delete the unmarked document" do
3936
+ expect(person.preferences(true)[1].name).to eq("New Title")
3937
+ end
3938
+
3939
+ it "does not add additional documents" do
3940
+ expect(person.preferences(true).size).to eq(2)
3941
+ end
3942
+ end
3943
+ end
3944
+ end
3945
+
3946
+ [ 0, "0", false, "false" ].each do |falsehood|
3947
+
3948
+ context "when passed a #{falsehood} with destroy" do
3949
+
3950
+ before do
3951
+ person.preferences_attributes =
3952
+ {
3953
+ "0" => { "id" => preference_one.id, "_destroy" => falsehood },
3954
+ "1" => { "id" => preference_two.id, "name" => "New Title" }
3955
+ }
3956
+ end
3957
+
3958
+ context "when reloading" do
3959
+
3960
+ it "does not delete the marked document" do
3961
+ expect(person.preferences(true).size).to eq(2)
3962
+ end
3963
+
3964
+ it "does not delete the unmarked document" do
3965
+ expect(person.preferences(true)[1].name).to eq("New Title")
3966
+ end
3967
+ end
3968
+ end
3969
+ end
3970
+ end
3971
+ end
3972
+ end
3973
+ end
3974
+
3975
+ context "when no ids are passed" do
3976
+
3977
+ context "when no destroy attributes are passed" do
3978
+
3979
+ before do
3980
+ person.preferences_attributes =
3981
+ {
3982
+ "4" => { "name" => "Third" },
3983
+ "1" => { "name" => "First" },
3984
+ "2" => { "name" => "Second" }
3985
+ }
3986
+ end
3987
+
3988
+ it "builds a new first document" do
3989
+ expect(person.preferences.first.name).to eq("First")
3990
+ end
3991
+
3992
+ it "builds a new second document" do
3993
+ expect(person.preferences.second.name).to eq("Second")
3994
+ end
3995
+
3996
+ it "builds a new third document" do
3997
+ expect(person.preferences.third.name).to eq("Third")
3998
+ end
3999
+
4000
+ it "does not add extra documents" do
4001
+ expect(person.preferences.size).to eq(3)
4002
+ end
4003
+
4004
+ it "adds the documents in the sorted hash key order" do
4005
+ expect(person.preferences.map(&:name)).to eq(
4006
+ [ "First", "Second", "Third" ]
4007
+ )
4008
+ end
4009
+ end
4010
+
4011
+ context "when a reject block is supplied" do
4012
+
4013
+ before do
4014
+ Person.send(:undef_method, :preferences_attributes=)
4015
+ Person.accepts_nested_attributes_for \
4016
+ :preferences, reject_if: ->(attrs){ attrs["name"].blank? }
4017
+ end
4018
+
4019
+ after do
4020
+ Person.send(:undef_method, :preferences_attributes=)
4021
+ Person.accepts_nested_attributes_for :preferences
4022
+ end
4023
+
4024
+ context "when the attributes match" do
4025
+
4026
+ before do
4027
+ person.preferences_attributes =
4028
+ { "3" => { "content" => "My first blog" } }
4029
+ end
4030
+
4031
+ it "does not add the new document" do
4032
+ expect(person.preferences).to be_empty
4033
+ end
4034
+ end
4035
+
4036
+ context "when the attributes do not match" do
4037
+
4038
+ before do
4039
+ person.preferences_attributes =
4040
+ { "3" => { "name" => "Blogging" } }
4041
+ end
4042
+
4043
+ it "adds the new document" do
4044
+ expect(person.preferences.size).to eq(1)
4045
+ end
4046
+
4047
+ it "sets the correct attributes" do
4048
+ expect(person.preferences.first.name).to eq("Blogging")
4049
+ end
4050
+ end
4051
+ end
4052
+
4053
+ context "when :reject_if => :all_blank is supplied" do
4054
+
4055
+ before do
4056
+ Person.send(:undef_method, :preferences_attributes=)
4057
+ Person.accepts_nested_attributes_for \
4058
+ :preferences, reject_if: :all_blank
4059
+ end
4060
+
4061
+ after do
4062
+ Person.send(:undef_method, :preferences_attributes=)
4063
+ Person.accepts_nested_attributes_for :preferences
4064
+ end
4065
+
4066
+ context "when all attributes are empty" do
4067
+
4068
+ before do
4069
+ person.preferences_attributes =
4070
+ { "3" => { "content" => "" } }
4071
+ end
4072
+
4073
+ it "does not add the new document" do
4074
+ expect(person.preferences).to be_empty
4075
+ end
4076
+ end
4077
+
4078
+ context "when an attribute is non-empty" do
4079
+
4080
+ before do
4081
+ person.preferences_attributes =
4082
+ { "3" => { "name" => "Blogging" } }
4083
+ end
4084
+
4085
+ it "adds the new document" do
4086
+ expect(person.preferences.size).to eq(1)
4087
+ end
4088
+
4089
+ it "sets the correct attributes" do
4090
+ expect(person.preferences.first.name).to eq("Blogging")
4091
+ end
4092
+ end
4093
+ end
4094
+
4095
+ context "when destroy attributes are passed" do
4096
+
4097
+ context "when allow_destroy is true" do
4098
+
4099
+ before do
4100
+ Person.send(:undef_method, :preferences_attributes=)
4101
+ Person.accepts_nested_attributes_for :preferences, allow_destroy: true
4102
+ end
4103
+
4104
+ after do
4105
+ Person.send(:undef_method, :preferences_attributes=)
4106
+ Person.accepts_nested_attributes_for :preferences
4107
+ end
4108
+
4109
+ [ 1, "1", true, "true" ].each do |truth|
4110
+
4111
+ context "when passed a #{truth} with destroy" do
4112
+
4113
+ before do
4114
+ person.preferences_attributes =
4115
+ {
4116
+ "0" => { "name" => "New Blog", "_destroy" => truth },
4117
+ "1" => { "name" => "Blog Two" }
4118
+ }
4119
+ end
4120
+
4121
+ it "ignores the marked document" do
4122
+ expect(person.preferences.size).to eq(1)
4123
+ end
4124
+
4125
+ it "adds the new unmarked document" do
4126
+ expect(person.preferences.first.name).to eq("Blog Two")
4127
+ end
4128
+ end
4129
+ end
4130
+
4131
+ [ 0, "0", false, "false" ].each do |falsehood|
4132
+
4133
+ context "when passed a #{falsehood} with destroy" do
4134
+
4135
+ before do
4136
+ person.preferences_attributes =
4137
+ {
4138
+ "0" => { "name" => "New Blog", "_destroy" => falsehood },
4139
+ "1" => { "name" => "Blog Two" }
4140
+ }
4141
+ end
4142
+
4143
+ it "adds the new marked document" do
4144
+ expect(person.preferences.first.name).to eq("New Blog")
4145
+ end
4146
+
4147
+ it "adds the new unmarked document" do
4148
+ expect(person.preferences.last.name).to eq("Blog Two")
4149
+ end
4150
+
4151
+ it "does not add extra documents" do
4152
+ expect(person.preferences.size).to eq(2)
4153
+ end
4154
+ end
4155
+ end
4156
+ end
4157
+
4158
+ context "when allow destroy is false" do
4159
+
4160
+ before do
4161
+ Person.send(:undef_method, :preferences_attributes=)
4162
+ Person.accepts_nested_attributes_for :preferences, allow_destroy: false
4163
+ end
4164
+
4165
+ after do
4166
+ Person.send(:undef_method, :preferences_attributes=)
4167
+ Person.accepts_nested_attributes_for :preferences
4168
+ end
4169
+
4170
+ [ 1, "1", true, "true" ].each do |truth|
4171
+
4172
+ context "when passed a #{truth} with destroy" do
4173
+
4174
+ before do
4175
+ person.preferences_attributes =
4176
+ {
4177
+ "0" => { "name" => "New Blog", "_destroy" => truth },
4178
+ "1" => { "name" => "Blog Two" }
4179
+ }
4180
+ end
4181
+
4182
+ it "adds the marked document" do
4183
+ expect(person.preferences.first.name).to eq("New Blog")
4184
+ end
4185
+
4186
+ it "adds the new unmarked document" do
4187
+ expect(person.preferences.last.name).to eq("Blog Two")
4188
+ end
4189
+
4190
+ it "adds the correct number of documents" do
4191
+ expect(person.preferences.size).to eq(2)
4192
+ end
4193
+ end
4194
+ end
4195
+
4196
+ [ 0, "0", false, "false" ].each do |falsehood|
4197
+
4198
+ context "when passed a #{falsehood} with destroy" do
4199
+
4200
+ before do
4201
+ person.preferences_attributes =
4202
+ {
4203
+ "0" => { "name" => "New Blog", "_destroy" => falsehood },
4204
+ "1" => { "name" => "Blog Two" }
4205
+ }
4206
+ end
4207
+
4208
+ it "adds the new marked document" do
4209
+ expect(person.preferences.first.name).to eq("New Blog")
4210
+ end
4211
+
4212
+ it "adds the new unmarked document" do
4213
+ expect(person.preferences.last.name).to eq("Blog Two")
4214
+ end
4215
+
4216
+ it "does not add extra documents" do
4217
+ expect(person.preferences.size).to eq(2)
4218
+ end
4219
+ end
4220
+ end
4221
+ end
4222
+
4223
+ context "when allow destroy is not defined" do
4224
+
4225
+ before do
4226
+ Person.send(:undef_method, :preferences_attributes=)
4227
+ Person.accepts_nested_attributes_for :preferences
4228
+ end
4229
+
4230
+ [ 1, "1", true, "true" ].each do |truth|
4231
+
4232
+ context "when passed a #{truth} with destroy" do
4233
+
4234
+ before do
4235
+ person.preferences_attributes =
4236
+ {
4237
+ "0" => { "name" => "New Blog", "_destroy" => truth },
4238
+ "1" => { "name" => "Blog Two" }
4239
+ }
4240
+ end
4241
+
4242
+ it "adds the marked document" do
4243
+ expect(person.preferences.first.name).to eq("New Blog")
4244
+ end
4245
+
4246
+ it "adds the new unmarked document" do
4247
+ expect(person.preferences.last.name).to eq("Blog Two")
4248
+ end
4249
+
4250
+ it "adds the correct number of documents" do
4251
+ expect(person.preferences.size).to eq(2)
4252
+ end
4253
+ end
4254
+ end
4255
+
4256
+ [ 0, "0", false, "false" ].each do |falsehood|
4257
+
4258
+ context "when passed a #{falsehood} with destroy" do
4259
+
4260
+ before do
4261
+ person.preferences_attributes =
4262
+ {
4263
+ "0" => { "name" => "New Blog", "_destroy" => falsehood },
4264
+ "1" => { "name" => "Blog Two" }
4265
+ }
4266
+ end
4267
+
4268
+ it "adds the new marked document" do
4269
+ expect(person.preferences.first.name).to eq("New Blog")
4270
+ end
4271
+
4272
+ it "adds the new unmarked document" do
4273
+ expect(person.preferences.last.name).to eq("Blog Two")
4274
+ end
4275
+
4276
+ it "does not add extra documents" do
4277
+ expect(person.preferences.size).to eq(2)
4278
+ end
4279
+ end
4280
+ end
4281
+ end
4282
+ end
4283
+ end
4284
+
4285
+ context "when the nested document is invalid" do
4286
+
4287
+ before do
4288
+ Person.validates_associated(:preferences)
4289
+ end
4290
+
4291
+ after do
4292
+ Person.reset_callbacks(:validate)
4293
+ end
4294
+
4295
+ before do
4296
+ person.preferences_attributes = {
4297
+ "0" => { name: 'x' }
4298
+ }
4299
+ end
4300
+
4301
+ it "propagates invalidity to parent" do
4302
+ expect(person.preferences.first).to_not be_valid
4303
+ expect(person).to_not be_valid
4304
+ end
4305
+ end
4306
+ end
4307
+ end
4308
+ end
4309
+
4310
+ describe "#update_attributes!" do
4311
+
4312
+ before do
4313
+ Person.send(:undef_method, :addresses_attributes=)
4314
+ Person.accepts_nested_attributes_for :addresses
4315
+ end
4316
+
4317
+ context "when embedding one level behind a has many" do
4318
+
4319
+ let(:node) do
4320
+ Node.create!
4321
+ end
4322
+
4323
+ let!(:server) do
4324
+ node.servers.create!(name: "prod")
4325
+ end
4326
+
4327
+ context "when adding a new embedded document" do
4328
+
4329
+ let(:attributes) do
4330
+ { servers_attributes:
4331
+ { "0" =>
4332
+ {
4333
+ _id: server.id,
4334
+ filesystems_attributes: {
4335
+ "0" => { name: "NFS" }
4336
+ }
4337
+ }
4338
+ }
4339
+ }
4340
+ end
4341
+
4342
+ before do
4343
+ node.update_attributes!(attributes)
4344
+ end
4345
+
4346
+ it "adds the new embedded document" do
4347
+ expect(server.reload.filesystems.first.name).to eq("NFS")
4348
+ end
4349
+
4350
+ it "does not add more than one document" do
4351
+ expect(server.reload.filesystems.count).to eq(1)
4352
+ end
4353
+ end
4354
+ end
4355
+
4356
+ context "when deleting the child document" do
4357
+
4358
+ let(:person) do
4359
+ Person.create!
4360
+ end
4361
+
4362
+ let!(:service) do
4363
+ person.services.create!(sid: "123")
4364
+ end
4365
+
4366
+ let(:attributes) do
4367
+ { services_attributes:
4368
+ { "0" =>
4369
+ { _id: service.id, sid: service.sid, _destroy: 1 }
4370
+ }
4371
+ }
4372
+ end
4373
+
4374
+ before do
4375
+ person.update_attributes!(attributes)
4376
+ end
4377
+
4378
+ it "removes the document from the parent" do
4379
+ expect(person.services).to be_empty
4380
+ end
4381
+
4382
+ it "deletes the document" do
4383
+ expect(service).to be_destroyed
4384
+ end
4385
+
4386
+ it "runs the before destroy callbacks" do
4387
+ expect(service.before_destroy_called).to be true
4388
+ end
4389
+
4390
+ it "runs the after destroy callbacks" do
4391
+ expect(service.after_destroy_called).to be true
4392
+ end
4393
+
4394
+ it "clears the delayed atomic pulls from the parent" do
4395
+ expect(person.delayed_atomic_pulls).to be_empty
4396
+ end
4397
+ end
4398
+
4399
+ context "when nesting multiple levels and parent is timestamped" do
4400
+
4401
+ after do
4402
+ Address.reset_callbacks(:save)
4403
+ end
4404
+
4405
+ let(:dokument) do
4406
+ Dokument.create!
4407
+ end
4408
+
4409
+ let!(:address) do
4410
+ dokument.addresses.create!(street: "hobrecht")
4411
+ end
4412
+
4413
+ let!(:location) do
4414
+ address.locations.create!(name: "work")
4415
+ end
4416
+
4417
+ let(:attributes) do
4418
+ {
4419
+ locations_attributes: {
4420
+ a: { name: "home" }
4421
+ }
4422
+ }
4423
+ end
4424
+
4425
+ before do
4426
+ address.update_attributes!(attributes)
4427
+ address.reload
4428
+ end
4429
+
4430
+ it "does not add any extra locations" do
4431
+ expect(address.locations.size).to eq(2)
4432
+ end
4433
+ end
4434
+
4435
+ context "when nesting multiple levels" do
4436
+
4437
+ let!(:person) do
4438
+ Person.create!
4439
+ end
4440
+
4441
+ context "when second level is a one to many" do
4442
+
4443
+ let(:person_one) do
4444
+ Person.create!
4445
+ end
4446
+
4447
+ let!(:address_one) do
4448
+ person_one.addresses.create!(street: "hobrecht")
4449
+ end
4450
+
4451
+ let!(:location_one) do
4452
+ address_one.locations.create!(name: "home")
4453
+ end
4454
+
4455
+ context "when destroying a second level document" do
4456
+
4457
+ let(:attributes) do
4458
+ { addresses_attributes:
4459
+ { "0" =>
4460
+ {
4461
+ _id: address_one.id,
4462
+ locations_attributes: { "0" => { _id: location_one.id, _destroy: true }}
4463
+ }
4464
+ }
4465
+ }
4466
+ end
4467
+
4468
+ before do
4469
+ person_one.update_attributes!(attributes)
4470
+ end
4471
+
4472
+ it "deletes the document from the relation" do
4473
+ expect(address_one.locations).to be_empty
4474
+ end
4475
+
4476
+ it "persists the change" do
4477
+ expect(address_one.reload.locations).to be_empty
4478
+ end
4479
+ end
4480
+
4481
+ context "when destroying a second level document with callbacks" do
4482
+
4483
+ let(:band) do
4484
+ Band.create!(name: "Tool")
4485
+ end
4486
+
4487
+ let(:record) do
4488
+ band.records.create!(name: "Undertow")
4489
+ end
4490
+
4491
+ let!(:track) do
4492
+ record.tracks.create!(name: "Sober")
4493
+ end
4494
+
4495
+ context "when cascading callbacks" do
4496
+
4497
+ before do
4498
+ Band.accepts_nested_attributes_for :records
4499
+ Record.accepts_nested_attributes_for :tracks, allow_destroy: true
4500
+ end
4501
+
4502
+ after do
4503
+ Band.send(:undef_method, :records_attributes=)
4504
+ Record.send(:undef_method, :tracks_attributes=)
4505
+ end
4506
+
4507
+ let(:attributes) do
4508
+ { records_attributes:
4509
+ { "0" =>
4510
+ {
4511
+ _id: record.id,
4512
+ tracks_attributes: { "0" => { _id: track.id, _destroy: true }}
4513
+ }
4514
+ }
4515
+ }
4516
+ end
4517
+
4518
+ before do
4519
+ band.update_attributes!(attributes)
4520
+ end
4521
+
4522
+ it "removes the child from the relation" do
4523
+ expect(record.tracks).to be_empty
4524
+ end
4525
+
4526
+ it "deletes the child document" do
4527
+ expect(track).to be_destroyed
4528
+ end
4529
+
4530
+ it "runs the child's callbacks" do
4531
+ expect(track.before_destroy_called).to be true
4532
+ end
4533
+ end
4534
+ end
4535
+
4536
+ context "when adding new documents in both levels" do
4537
+
4538
+ context "when no documents has previously existed" do
4539
+
4540
+ let(:attributes) do
4541
+ { addresses_attributes:
4542
+ { "0" =>
4543
+ {
4544
+ street: "Alexanderstr",
4545
+ locations_attributes: { "0" => { name: "Home" } }
4546
+ }
4547
+ }
4548
+ }
4549
+ end
4550
+
4551
+ before do
4552
+ person.update_attributes!(attributes)
4553
+ end
4554
+
4555
+ let(:address) do
4556
+ person.addresses.first
4557
+ end
4558
+
4559
+ let(:location) do
4560
+ address.locations.first
4561
+ end
4562
+
4563
+ it "adds the new first level embedded document" do
4564
+ expect(address.street).to eq("Alexanderstr")
4565
+ end
4566
+
4567
+ it "adds the nested embedded document" do
4568
+ expect(location.name).to eq("Home")
4569
+ end
4570
+ end
4571
+
4572
+ context "when adding to an existing document in the first level" do
4573
+
4574
+ let!(:address) do
4575
+ person.addresses.create!(street: "hobrecht")
4576
+ end
4577
+
4578
+ let!(:location) do
4579
+ address.locations.create!(name: "work")
4580
+ end
4581
+
4582
+ let(:attributes) do
4583
+ {
4584
+ addresses_attributes: {
4585
+ a: { id: address.id, locations_attributes: { b: { name: "home" }}},
4586
+ c: { street: "pfluger" }
4587
+ }
4588
+ }
4589
+ end
4590
+
4591
+ before do
4592
+ person.update_attributes!(attributes)
4593
+ person.reload
4594
+ end
4595
+
4596
+ it "adds the new location to the existing address" do
4597
+ expect(person.addresses.first.locations.count).to eq(2)
4598
+ end
4599
+
4600
+ it "adds the new address" do
4601
+ expect(person.addresses.count).to eq(2)
4602
+ end
4603
+ end
4604
+ end
4605
+ end
4606
+
4607
+ context "when the second level is a one to one" do
4608
+
4609
+ context "when the nested document is new" do
4610
+
4611
+ let(:attributes) do
4612
+ { addresses_attributes:
4613
+ { "0" =>
4614
+ {
4615
+ street: "Alexanderstr",
4616
+ code_attributes: { name: "Home" }
4617
+ }
4618
+ }
4619
+ }
4620
+ end
4621
+
4622
+ before do
4623
+ person.update_attributes!(attributes)
4624
+ end
4625
+
4626
+ let(:address) do
4627
+ person.addresses.first
4628
+ end
4629
+
4630
+ let(:code) do
4631
+ address.code
4632
+ end
4633
+
4634
+ it "adds the new first level embedded document" do
4635
+ expect(address.street).to eq("Alexanderstr")
4636
+ end
4637
+
4638
+ it "adds the nested embedded document" do
4639
+ expect(code.name).to eq("Home")
4640
+ end
4641
+ end
4642
+ end
4643
+
4644
+ context "when the nested document is getting updated" do
4645
+
4646
+ context "when the nested document is not polymorphic" do
4647
+
4648
+ let!(:address) do
4649
+ person.addresses.create!(street: "Alexanderstr", number: 1)
4650
+ end
4651
+
4652
+ let!(:code) do
4653
+ address.create_code(name: "Home")
4654
+ end
4655
+
4656
+ let(:attributes) do
4657
+ { addresses_attributes:
4658
+ { "0" =>
4659
+ {
4660
+ _id: address.id,
4661
+ number: 45,
4662
+ code_attributes: {
4663
+ _id: code.id,
4664
+ name: "Work"
4665
+ }
4666
+ }
4667
+ }
4668
+ }
4669
+ end
4670
+
4671
+ before do
4672
+ person.update_attributes!(attributes)
4673
+ end
4674
+
4675
+ it "updates the first level embedded document" do
4676
+ expect(address.number).to eq(45)
4677
+ end
4678
+
4679
+ it "updates the nested embedded document" do
4680
+ expect(code.name).to eq("Work")
4681
+ end
4682
+ end
4683
+
4684
+ context "when the nested document is polymorphic" do
4685
+
4686
+ context "when the first level is an embeds many" do
4687
+
4688
+ let!(:address) do
4689
+ person.addresses.create!(street: "Alexanderstr", number: 1)
4690
+ end
4691
+
4692
+ let!(:target) do
4693
+ address.create_target(name: "test")
4694
+ end
4695
+
4696
+ let(:attributes) do
4697
+ { addresses_attributes:
4698
+ { "0" =>
4699
+ {
4700
+ _id: address.id,
4701
+ number: 45,
4702
+ target_attributes: {
4703
+ _id: target.id,
4704
+ name: "updated"
4705
+ }
4706
+ }
4707
+ }
4708
+ }
4709
+ end
4710
+
4711
+ before do
4712
+ person.update_attributes!(attributes)
4713
+ end
4714
+
4715
+ it "updates the first level embedded document" do
4716
+ expect(address.number).to eq(45)
4717
+ end
4718
+
4719
+ it "updates the nested embedded document" do
4720
+ expect(target.name).to eq("updated")
4721
+ end
4722
+ end
4723
+
4724
+ context "when the first level is an embeds one" do
4725
+
4726
+ context "when the id is passed as a string" do
4727
+
4728
+ let!(:name) do
4729
+ person.create_name(first_name: "john", last_name: "doe")
4730
+ end
4731
+
4732
+ let!(:language) do
4733
+ name.create_language(name: "english")
4734
+ end
4735
+
4736
+ let(:attributes) do
4737
+ { name_attributes:
4738
+ {
4739
+ language_attributes: {
4740
+ _id: language.id.to_s,
4741
+ name: "deutsch"
4742
+ }
4743
+ }
4744
+ }
4745
+ end
4746
+
4747
+ before do
4748
+ person.update_attributes!(attributes)
4749
+ end
4750
+
4751
+ it "updates the nested embedded document" do
4752
+ expect(language.name).to eq("deutsch")
4753
+ end
4754
+ end
4755
+ end
4756
+ end
4757
+ end
4758
+ end
4759
+
4760
+ context "when the relation is a has many" do
4761
+
4762
+ context "when updating with valid attributes" do
4763
+
4764
+ let(:user) do
4765
+ User.create!
4766
+ end
4767
+
4768
+ let(:params) do
4769
+ { posts_attributes:
4770
+ { "0" => { title: "Testing" }}
4771
+ }
4772
+ end
4773
+
4774
+ before do
4775
+ user.update_attributes!(params)
4776
+ end
4777
+
4778
+ around do |example|
4779
+ original_relations = User.relations
4780
+ User.has_many :posts, foreign_key: :author_id, validate: false, autosave: true
4781
+ example.run
4782
+ user.relations = original_relations
4783
+ end
4784
+
4785
+ let(:post) do
4786
+ user.posts.first
4787
+ end
4788
+
4789
+ it "adds the new document to the relation" do
4790
+ expect(post.title).to eq("Testing")
4791
+ end
4792
+
4793
+ it "autosaves the relation" do
4794
+ expect(user.posts(true).first.title).to eq("Testing")
4795
+ end
4796
+ end
4797
+
4798
+ context "when the document is freshly loaded from the db" do
4799
+
4800
+ let!(:node) do
4801
+ Node.create!
4802
+ end
4803
+
4804
+ let!(:server) do
4805
+ node.servers.create!(name: "test")
4806
+ end
4807
+
4808
+ before do
4809
+ node.reload
4810
+ end
4811
+
4812
+ context "when updating invalid attributes" do
4813
+
4814
+ let!(:update) do
4815
+ node.update_attributes({
4816
+ servers_attributes: { "0" => { "_id" => server.id, "name" => "" }}
4817
+ })
4818
+ end
4819
+
4820
+ it "returns false" do
4821
+ expect(update).to be false
4822
+ end
4823
+
4824
+ it "does not update the child document" do
4825
+ expect(server.reload.name).to eq("test")
4826
+ end
4827
+
4828
+ it "adds the errors to the document" do
4829
+ expect(node.errors[:servers]).to_not be_nil
4830
+ end
4831
+ end
4832
+ end
4833
+ end
4834
+
4835
+ context "when the relation is an embeds many" do
4836
+
4837
+ let(:league) do
4838
+ League.create!
4839
+ end
4840
+
4841
+ let!(:division) do
4842
+ league.divisions.create!(name: "Old Name")
4843
+ end
4844
+
4845
+ context "when additional validation is set" do
4846
+
4847
+ before do
4848
+ League.validates_presence_of(:divisions)
4849
+ end
4850
+
4851
+ after do
4852
+ League.reset_callbacks(:validate)
4853
+ end
4854
+
4855
+ context "when validation fails" do
4856
+
4857
+ let(:division) do
4858
+ Division.new
4859
+ end
4860
+
4861
+ let(:league) do
4862
+ League.create!(divisions: [division])
4863
+ end
4864
+
4865
+ let(:error_raising_update) do
4866
+ league.update!(:divisions => nil)
4867
+ end
4868
+
4869
+ before do
4870
+ league.update(:divisions => nil)
4871
+ league.reload
4872
+ end
4873
+
4874
+ it "the update raises an error" do
4875
+ expect{ error_raising_update }.to raise_error(Mongoid::Errors::Validations)
4876
+ end
4877
+
4878
+ it "the update does not occur" do
4879
+ expect(league.divisions.first).to eq(division)
4880
+ end
4881
+
4882
+ it "the document is inaccurately marked destroyed (you fixed the bug if you broke this!)" do
4883
+ expect(division).to be_destroyed
4884
+ end
4885
+ end
4886
+ end
4887
+
4888
+ context "when no additional validation is set" do
4889
+
4890
+ let(:params) do
4891
+ { divisions_attributes:
4892
+ { "0" => { id: division.id.to_s, name: "New Name" }}
4893
+ }
4894
+ end
4895
+
4896
+ before do
4897
+ league.update_attributes!(params)
4898
+ end
4899
+
4900
+ it "sets the nested attributes" do
4901
+ expect(league.reload.divisions.first.name).to eq("New Name")
4902
+ end
4903
+
4904
+ context "with corrupted data" do
4905
+
4906
+ before do
4907
+ league[:league] = params
4908
+ end
4909
+
4910
+ let(:new_params) do
4911
+ { divisions_attributes:
4912
+ { "0" => { id: division.id.to_s, name: "Name" }}
4913
+ }
4914
+ end
4915
+
4916
+ before do
4917
+ league.update_attributes!(new_params)
4918
+ end
4919
+
4920
+ it "sets the nested attributes" do
4921
+ expect(league.reload.divisions.first.name).to eq("Name")
4922
+ end
4923
+ end
4924
+ end
4925
+ end
4926
+ end
4927
+
4928
+ context "when destroying has_many child using nested attributes" do
4929
+ let(:school) do
4930
+ School.create
4931
+ end
4932
+
4933
+ let!(:student) do
4934
+ school.students.create
4935
+ end
4936
+
4937
+ before do
4938
+ school.attributes = {
4939
+ '_id': school.id,
4940
+ 'students_attributes': [{
4941
+ '_id': student.id,
4942
+ '_destroy': 1
4943
+ }]
4944
+ }
4945
+ end
4946
+
4947
+ it "is able to access the parent in the after_destroy callback" do
4948
+ expect(school.after_destroy_triggered).to eq(true)
4949
+ end
4950
+ end
4951
+
4952
+ context "when destroying has_many child using nested attributes" do
4953
+ let(:school) do
4954
+ HabtmmSchool.create!(students: [student])
4955
+ end
4956
+
4957
+ let(:student) do
4958
+ HabtmmStudent.create!
4959
+ end
4960
+
4961
+ before do
4962
+ student.schools << school
4963
+ school.attributes = {
4964
+ '_id': school.id,
4965
+ 'students_attributes': [{
4966
+ '_id': student.id,
4967
+ '_destroy': 1
4968
+ }]
4969
+ }
4970
+ end
4971
+
4972
+ it "is able to access the parent in the after_destroy callback" do
4973
+ expect(school.reload.after_destroy_triggered).to eq(true)
4974
+ end
4975
+ end
4976
+
4977
+ context "when using a multi-leveled nested attribute on a referenced association" do
4978
+ let(:author) { NestedAuthor.create }
4979
+ let(:one_level_params) { { post_attributes: { title: 'test' } } }
4980
+ let(:two_levels_params) { { post_attributes: { comments_attributes: [ { body: 'test' } ] } } }
4981
+
4982
+ it "creates a 1st-depth child model" do
4983
+ author.update_attributes(one_level_params)
4984
+ expect(author.post.persisted?).to be true
4985
+ end
4986
+
4987
+ it "creates a 1st-depth child model, and a 2nd-depth child model" do
4988
+ author.update_attributes(two_levels_params)
4989
+ expect(author.post.comments.count).to eq 1
4990
+ end
4991
+
4992
+ context "the 1st-depth child model already exists" do
4993
+ it "creates a 2nd-depth child model" do
4994
+ author.create_post(title: 'test')
4995
+ author.update_attributes(two_levels_params)
4996
+ expect(author.post.comments.count).to eq 1
4997
+ end
4998
+ end
4999
+ end
5000
+ end