mongoid-ultra 9.0.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (1086) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +156 -0
  4. data/Rakefile +34 -0
  5. data/lib/config/locales/en.yml +706 -0
  6. data/lib/mongoid/association/accessors.rb +430 -0
  7. data/lib/mongoid/association/bindable.rb +227 -0
  8. data/lib/mongoid/association/builders.rb +86 -0
  9. data/lib/mongoid/association/constrainable.rb +42 -0
  10. data/lib/mongoid/association/depending.rb +128 -0
  11. data/lib/mongoid/association/eager.rb +159 -0
  12. data/lib/mongoid/association/eager_loadable.rb +58 -0
  13. data/lib/mongoid/association/embedded/batchable.rb +396 -0
  14. data/lib/mongoid/association/embedded/cyclic.rb +102 -0
  15. data/lib/mongoid/association/embedded/eager.rb +22 -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 +124 -0
  19. data/lib/mongoid/association/embedded/embedded_in.rb +141 -0
  20. data/lib/mongoid/association/embedded/embeds_many/binding.rb +42 -0
  21. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +46 -0
  22. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +584 -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 +183 -0
  27. data/lib/mongoid/association/embedded/embeds_one.rb +150 -0
  28. data/lib/mongoid/association/embedded.rb +7 -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 +154 -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 +127 -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/has_and_belongs_to_many/binding.rb +72 -0
  47. data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +40 -0
  48. data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +53 -0
  49. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +345 -0
  50. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +277 -0
  51. data/lib/mongoid/association/referenced/has_many/binding.rb +36 -0
  52. data/lib/mongoid/association/referenced/has_many/buildable.rb +38 -0
  53. data/lib/mongoid/association/referenced/has_many/eager.rb +44 -0
  54. data/lib/mongoid/association/referenced/has_many/enumerable.rb +490 -0
  55. data/lib/mongoid/association/referenced/has_many/proxy.rb +552 -0
  56. data/lib/mongoid/association/referenced/has_many.rb +251 -0
  57. data/lib/mongoid/association/referenced/has_one/binding.rb +42 -0
  58. data/lib/mongoid/association/referenced/has_one/buildable.rb +74 -0
  59. data/lib/mongoid/association/referenced/has_one/eager.rb +36 -0
  60. data/lib/mongoid/association/referenced/has_one/proxy.rb +108 -0
  61. data/lib/mongoid/association/referenced/has_one.rb +184 -0
  62. data/lib/mongoid/association/referenced/syncable.rb +155 -0
  63. data/lib/mongoid/association/referenced.rb +9 -0
  64. data/lib/mongoid/association/reflections.rb +69 -0
  65. data/lib/mongoid/association/relatable.rb +489 -0
  66. data/lib/mongoid/association.rb +135 -0
  67. data/lib/mongoid/atomic/modifiers.rb +297 -0
  68. data/lib/mongoid/atomic/paths/embedded/many.rb +60 -0
  69. data/lib/mongoid/atomic/paths/embedded/one.rb +40 -0
  70. data/lib/mongoid/atomic/paths/embedded.rb +27 -0
  71. data/lib/mongoid/atomic/paths/root.rb +36 -0
  72. data/lib/mongoid/atomic/paths.rb +4 -0
  73. data/lib/mongoid/atomic.rb +332 -0
  74. data/lib/mongoid/attributes/dynamic.rb +141 -0
  75. data/lib/mongoid/attributes/nested.rb +93 -0
  76. data/lib/mongoid/attributes/processing.rb +139 -0
  77. data/lib/mongoid/attributes/projector.rb +119 -0
  78. data/lib/mongoid/attributes/readonly.rb +73 -0
  79. data/lib/mongoid/attributes.rb +368 -0
  80. data/lib/mongoid/cacheable.rb +33 -0
  81. data/lib/mongoid/changeable.rb +520 -0
  82. data/lib/mongoid/clients/factory.rb +115 -0
  83. data/lib/mongoid/clients/options.rb +119 -0
  84. data/lib/mongoid/clients/sessions.rb +146 -0
  85. data/lib/mongoid/clients/storage_options.rb +76 -0
  86. data/lib/mongoid/clients/validators/storage.rb +46 -0
  87. data/lib/mongoid/clients/validators.rb +3 -0
  88. data/lib/mongoid/clients.rb +79 -0
  89. data/lib/mongoid/collection_configurable.rb +58 -0
  90. data/lib/mongoid/composable.rb +132 -0
  91. data/lib/mongoid/config/defaults.rb +45 -0
  92. data/lib/mongoid/config/encryption.rb +203 -0
  93. data/lib/mongoid/config/environment.rb +82 -0
  94. data/lib/mongoid/config/introspection.rb +150 -0
  95. data/lib/mongoid/config/options.rb +86 -0
  96. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  97. data/lib/mongoid/config/validators/client.rb +128 -0
  98. data/lib/mongoid/config/validators/option.rb +24 -0
  99. data/lib/mongoid/config/validators.rb +5 -0
  100. data/lib/mongoid/config.rb +380 -0
  101. data/lib/mongoid/contextual/aggregable/memory.rb +122 -0
  102. data/lib/mongoid/contextual/aggregable/mongo.rb +140 -0
  103. data/lib/mongoid/contextual/aggregable/none.rb +65 -0
  104. data/lib/mongoid/contextual/aggregable.rb +17 -0
  105. data/lib/mongoid/contextual/atomic.rb +245 -0
  106. data/lib/mongoid/contextual/command.rb +32 -0
  107. data/lib/mongoid/contextual/geo_near.rb +236 -0
  108. data/lib/mongoid/contextual/map_reduce.rb +230 -0
  109. data/lib/mongoid/contextual/memory.rb +770 -0
  110. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  111. data/lib/mongoid/contextual/mongo.rb +1065 -0
  112. data/lib/mongoid/contextual/none.rb +326 -0
  113. data/lib/mongoid/contextual/queryable.rb +24 -0
  114. data/lib/mongoid/contextual.rb +66 -0
  115. data/lib/mongoid/copyable.rb +115 -0
  116. data/lib/mongoid/criteria/findable.rb +143 -0
  117. data/lib/mongoid/criteria/includable.rb +93 -0
  118. data/lib/mongoid/criteria/inspectable.rb +24 -0
  119. data/lib/mongoid/criteria/marshalable.rb +55 -0
  120. data/lib/mongoid/criteria/modifiable.rb +235 -0
  121. data/lib/mongoid/criteria/options.rb +24 -0
  122. data/lib/mongoid/criteria/permission.rb +71 -0
  123. data/lib/mongoid/criteria/queryable/aggregable.rb +109 -0
  124. data/lib/mongoid/criteria/queryable/expandable.rb +68 -0
  125. data/lib/mongoid/criteria/queryable/extensions/array.rb +151 -0
  126. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +55 -0
  127. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +33 -0
  128. data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
  129. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +52 -0
  130. data/lib/mongoid/criteria/queryable/extensions/hash.rb +163 -0
  131. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +75 -0
  132. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +73 -0
  133. data/lib/mongoid/criteria/queryable/extensions/object.rb +182 -0
  134. data/lib/mongoid/criteria/queryable/extensions/range.rb +102 -0
  135. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +72 -0
  136. data/lib/mongoid/criteria/queryable/extensions/set.rb +33 -0
  137. data/lib/mongoid/criteria/queryable/extensions/string.rb +112 -0
  138. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +64 -0
  139. data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
  140. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +66 -0
  141. data/lib/mongoid/criteria/queryable/extensions.rb +25 -0
  142. data/lib/mongoid/criteria/queryable/key.rb +177 -0
  143. data/lib/mongoid/criteria/queryable/macroable.rb +26 -0
  144. data/lib/mongoid/criteria/queryable/mergeable.rb +434 -0
  145. data/lib/mongoid/criteria/queryable/optional.rb +380 -0
  146. data/lib/mongoid/criteria/queryable/options.rb +136 -0
  147. data/lib/mongoid/criteria/queryable/pipeline.rb +106 -0
  148. data/lib/mongoid/criteria/queryable/selectable.rb +952 -0
  149. data/lib/mongoid/criteria/queryable/selector.rb +289 -0
  150. data/lib/mongoid/criteria/queryable/smash.rb +128 -0
  151. data/lib/mongoid/criteria/queryable/storable.rb +237 -0
  152. data/lib/mongoid/criteria/queryable.rb +90 -0
  153. data/lib/mongoid/criteria/scopable.rb +166 -0
  154. data/lib/mongoid/criteria/translator.rb +45 -0
  155. data/lib/mongoid/criteria.rb +570 -0
  156. data/lib/mongoid/deprecable.rb +36 -0
  157. data/lib/mongoid/deprecation.rb +25 -0
  158. data/lib/mongoid/document.rb +389 -0
  159. data/lib/mongoid/encryptable.rb +49 -0
  160. data/lib/mongoid/equality.rb +63 -0
  161. data/lib/mongoid/errors/ambiguous_relationship.rb +50 -0
  162. data/lib/mongoid/errors/attribute_not_loaded.rb +33 -0
  163. data/lib/mongoid/errors/callback.rb +24 -0
  164. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  165. data/lib/mongoid/errors/criteria_argument_required.rb +18 -0
  166. data/lib/mongoid/errors/delete_restriction.rb +26 -0
  167. data/lib/mongoid/errors/document_not_destroyed.rb +22 -0
  168. data/lib/mongoid/errors/document_not_found.rb +125 -0
  169. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  170. data/lib/mongoid/errors/empty_config_file.rb +25 -0
  171. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  172. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +19 -0
  173. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  174. data/lib/mongoid/errors/invalid_auto_encryption_configuration.rb +32 -0
  175. data/lib/mongoid/errors/invalid_collection.rb +19 -0
  176. data/lib/mongoid/errors/invalid_config_file.rb +25 -0
  177. data/lib/mongoid/errors/invalid_config_option.rb +26 -0
  178. data/lib/mongoid/errors/invalid_dependent_strategy.rb +31 -0
  179. data/lib/mongoid/errors/invalid_discriminator_key_target.rb +24 -0
  180. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  181. data/lib/mongoid/errors/invalid_elem_match_operator.rb +32 -0
  182. data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +25 -0
  183. data/lib/mongoid/errors/invalid_estimated_count_scoping.rb +25 -0
  184. data/lib/mongoid/errors/invalid_expression_operator.rb +27 -0
  185. data/lib/mongoid/errors/invalid_field.rb +65 -0
  186. data/lib/mongoid/errors/invalid_field_operator.rb +32 -0
  187. data/lib/mongoid/errors/invalid_field_option.rb +34 -0
  188. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  189. data/lib/mongoid/errors/invalid_find.rb +18 -0
  190. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  191. data/lib/mongoid/errors/invalid_includes.rb +31 -0
  192. data/lib/mongoid/errors/invalid_index.rb +27 -0
  193. data/lib/mongoid/errors/invalid_options.rb +27 -0
  194. data/lib/mongoid/errors/invalid_path.rb +20 -0
  195. data/lib/mongoid/errors/invalid_persistence_option.rb +26 -0
  196. data/lib/mongoid/errors/invalid_query.rb +40 -0
  197. data/lib/mongoid/errors/invalid_relation.rb +61 -0
  198. data/lib/mongoid/errors/invalid_relation_option.rb +28 -0
  199. data/lib/mongoid/errors/invalid_scope.rb +23 -0
  200. data/lib/mongoid/errors/invalid_session_nesting.rb +16 -0
  201. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +39 -0
  202. data/lib/mongoid/errors/invalid_storage_options.rb +26 -0
  203. data/lib/mongoid/errors/invalid_storage_parent.rb +27 -0
  204. data/lib/mongoid/errors/invalid_time.rb +21 -0
  205. data/lib/mongoid/errors/invalid_transaction_nesting.rb +16 -0
  206. data/lib/mongoid/errors/inverse_not_found.rb +28 -0
  207. data/lib/mongoid/errors/mixed_client_configuration.rb +27 -0
  208. data/lib/mongoid/errors/mixed_relations.rb +31 -0
  209. data/lib/mongoid/errors/mongoid_error.rb +91 -0
  210. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +27 -0
  211. data/lib/mongoid/errors/no_client_config.rb +21 -0
  212. data/lib/mongoid/errors/no_client_database.rb +26 -0
  213. data/lib/mongoid/errors/no_client_hosts.rb +26 -0
  214. data/lib/mongoid/errors/no_clients_config.rb +19 -0
  215. data/lib/mongoid/errors/no_default_client.rb +22 -0
  216. data/lib/mongoid/errors/no_environment.rb +18 -0
  217. data/lib/mongoid/errors/no_map_reduce_output.rb +23 -0
  218. data/lib/mongoid/errors/no_metadata.rb +20 -0
  219. data/lib/mongoid/errors/no_parent.rb +23 -0
  220. data/lib/mongoid/errors/readonly_attribute.rb +24 -0
  221. data/lib/mongoid/errors/readonly_document.rb +21 -0
  222. data/lib/mongoid/errors/rollback.rb +14 -0
  223. data/lib/mongoid/errors/scope_overwrite.rb +22 -0
  224. data/lib/mongoid/errors/sessions_not_supported.rb +16 -0
  225. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +22 -0
  226. data/lib/mongoid/errors/transaction_error.rb +22 -0
  227. data/lib/mongoid/errors/transactions_not_supported.rb +16 -0
  228. data/lib/mongoid/errors/unknown_attribute.rb +24 -0
  229. data/lib/mongoid/errors/unknown_model.rb +24 -0
  230. data/lib/mongoid/errors/unsaved_document.rb +20 -0
  231. data/lib/mongoid/errors/unsupported_javascript.rb +26 -0
  232. data/lib/mongoid/errors/validations.rb +30 -0
  233. data/lib/mongoid/errors.rb +73 -0
  234. data/lib/mongoid/evolvable.rb +18 -0
  235. data/lib/mongoid/extensions/array.rb +173 -0
  236. data/lib/mongoid/extensions/big_decimal.rb +90 -0
  237. data/lib/mongoid/extensions/binary.rb +42 -0
  238. data/lib/mongoid/extensions/boolean.rb +26 -0
  239. data/lib/mongoid/extensions/date.rb +87 -0
  240. data/lib/mongoid/extensions/date_time.rb +60 -0
  241. data/lib/mongoid/extensions/decimal128.rb +36 -0
  242. data/lib/mongoid/extensions/false_class.rb +35 -0
  243. data/lib/mongoid/extensions/float.rb +55 -0
  244. data/lib/mongoid/extensions/hash.rb +248 -0
  245. data/lib/mongoid/extensions/integer.rb +63 -0
  246. data/lib/mongoid/extensions/module.rb +27 -0
  247. data/lib/mongoid/extensions/nil_class.rb +30 -0
  248. data/lib/mongoid/extensions/object.rb +250 -0
  249. data/lib/mongoid/extensions/object_id.rb +49 -0
  250. data/lib/mongoid/extensions/range.rb +108 -0
  251. data/lib/mongoid/extensions/raw_value.rb +32 -0
  252. data/lib/mongoid/extensions/regexp.rb +34 -0
  253. data/lib/mongoid/extensions/set.rb +57 -0
  254. data/lib/mongoid/extensions/string.rb +171 -0
  255. data/lib/mongoid/extensions/symbol.rb +38 -0
  256. data/lib/mongoid/extensions/time.rb +105 -0
  257. data/lib/mongoid/extensions/time_with_zone.rb +74 -0
  258. data/lib/mongoid/extensions/true_class.rb +35 -0
  259. data/lib/mongoid/extensions.rb +27 -0
  260. data/lib/mongoid/factory.rb +134 -0
  261. data/lib/mongoid/fields/encrypted.rb +41 -0
  262. data/lib/mongoid/fields/foreign_key.rb +166 -0
  263. data/lib/mongoid/fields/localized.rb +99 -0
  264. data/lib/mongoid/fields/standard.rb +241 -0
  265. data/lib/mongoid/fields/validators/macro.rb +125 -0
  266. data/lib/mongoid/fields/validators.rb +3 -0
  267. data/lib/mongoid/fields.rb +851 -0
  268. data/lib/mongoid/findable.rb +243 -0
  269. data/lib/mongoid/indexable/specification.rb +138 -0
  270. data/lib/mongoid/indexable/validators/options.rb +110 -0
  271. data/lib/mongoid/indexable.rb +148 -0
  272. data/lib/mongoid/inspectable.rb +52 -0
  273. data/lib/mongoid/interceptable.rb +320 -0
  274. data/lib/mongoid/loadable.rb +82 -0
  275. data/lib/mongoid/loggable.rb +66 -0
  276. data/lib/mongoid/matchable.rb +23 -0
  277. data/lib/mongoid/matcher/all.rb +22 -0
  278. data/lib/mongoid/matcher/and.rb +21 -0
  279. data/lib/mongoid/matcher/bits.rb +41 -0
  280. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  281. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  282. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  283. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  284. data/lib/mongoid/matcher/elem_match.rb +36 -0
  285. data/lib/mongoid/matcher/elem_match_expression.rb +20 -0
  286. data/lib/mongoid/matcher/eq.rb +11 -0
  287. data/lib/mongoid/matcher/eq_impl.rb +62 -0
  288. data/lib/mongoid/matcher/eq_impl_with_regexp.rb +25 -0
  289. data/lib/mongoid/matcher/exists.rb +15 -0
  290. data/lib/mongoid/matcher/expression.rb +35 -0
  291. data/lib/mongoid/matcher/expression_operator.rb +19 -0
  292. data/lib/mongoid/matcher/field_expression.rb +62 -0
  293. data/lib/mongoid/matcher/field_operator.rb +54 -0
  294. data/lib/mongoid/matcher/gt.rb +17 -0
  295. data/lib/mongoid/matcher/gte.rb +17 -0
  296. data/lib/mongoid/matcher/in.rb +25 -0
  297. data/lib/mongoid/matcher/lt.rb +17 -0
  298. data/lib/mongoid/matcher/lte.rb +17 -0
  299. data/lib/mongoid/matcher/mod.rb +17 -0
  300. data/lib/mongoid/matcher/ne.rb +16 -0
  301. data/lib/mongoid/matcher/nin.rb +11 -0
  302. data/lib/mongoid/matcher/nor.rb +25 -0
  303. data/lib/mongoid/matcher/not.rb +29 -0
  304. data/lib/mongoid/matcher/or.rb +21 -0
  305. data/lib/mongoid/matcher/regex.rb +41 -0
  306. data/lib/mongoid/matcher/size.rb +26 -0
  307. data/lib/mongoid/matcher/type.rb +99 -0
  308. data/lib/mongoid/matcher.rb +115 -0
  309. data/lib/mongoid/persistable/creatable.rb +184 -0
  310. data/lib/mongoid/persistable/deletable.rb +136 -0
  311. data/lib/mongoid/persistable/destroyable.rb +80 -0
  312. data/lib/mongoid/persistable/incrementable.rb +35 -0
  313. data/lib/mongoid/persistable/logical.rb +36 -0
  314. data/lib/mongoid/persistable/maxable.rb +36 -0
  315. data/lib/mongoid/persistable/minable.rb +36 -0
  316. data/lib/mongoid/persistable/multipliable.rb +35 -0
  317. data/lib/mongoid/persistable/poppable.rb +36 -0
  318. data/lib/mongoid/persistable/pullable.rb +50 -0
  319. data/lib/mongoid/persistable/pushable.rb +66 -0
  320. data/lib/mongoid/persistable/renamable.rb +37 -0
  321. data/lib/mongoid/persistable/savable.rb +59 -0
  322. data/lib/mongoid/persistable/settable.rb +93 -0
  323. data/lib/mongoid/persistable/unsettable.rb +36 -0
  324. data/lib/mongoid/persistable/updatable.rb +233 -0
  325. data/lib/mongoid/persistable/upsertable.rb +82 -0
  326. data/lib/mongoid/persistable.rb +317 -0
  327. data/lib/mongoid/persistence_context.rb +275 -0
  328. data/lib/mongoid/positional.rb +72 -0
  329. data/lib/mongoid/query_cache.rb +64 -0
  330. data/lib/mongoid/railtie.rb +122 -0
  331. data/lib/mongoid/railties/console_sandbox.rb +41 -0
  332. data/lib/mongoid/railties/controller_runtime.rb +88 -0
  333. data/lib/mongoid/railties/database.rake +93 -0
  334. data/lib/mongoid/reloadable.rb +94 -0
  335. data/lib/mongoid/scopable.rb +323 -0
  336. data/lib/mongoid/selectable.rb +49 -0
  337. data/lib/mongoid/serializable.rb +170 -0
  338. data/lib/mongoid/shardable.rb +154 -0
  339. data/lib/mongoid/stateful.rb +155 -0
  340. data/lib/mongoid/stringified_symbol.rb +52 -0
  341. data/lib/mongoid/tasks/database.rake +51 -0
  342. data/lib/mongoid/tasks/database.rb +214 -0
  343. data/lib/mongoid/tasks/encryption.rake +19 -0
  344. data/lib/mongoid/tasks/encryption.rb +102 -0
  345. data/lib/mongoid/threaded/lifecycle.rb +150 -0
  346. data/lib/mongoid/threaded.rb +396 -0
  347. data/lib/mongoid/timestamps/created/short.rb +20 -0
  348. data/lib/mongoid/timestamps/created.rb +34 -0
  349. data/lib/mongoid/timestamps/short.rb +11 -0
  350. data/lib/mongoid/timestamps/timeless.rb +95 -0
  351. data/lib/mongoid/timestamps/updated/short.rb +20 -0
  352. data/lib/mongoid/timestamps/updated.rb +44 -0
  353. data/lib/mongoid/timestamps.rb +17 -0
  354. data/lib/mongoid/touchable.rb +228 -0
  355. data/lib/mongoid/traversable.rb +337 -0
  356. data/lib/mongoid/utils.rb +22 -0
  357. data/lib/mongoid/validatable/associated.rb +47 -0
  358. data/lib/mongoid/validatable/format.rb +21 -0
  359. data/lib/mongoid/validatable/length.rb +21 -0
  360. data/lib/mongoid/validatable/localizable.rb +29 -0
  361. data/lib/mongoid/validatable/macros.rb +89 -0
  362. data/lib/mongoid/validatable/presence.rb +81 -0
  363. data/lib/mongoid/validatable/queryable.rb +29 -0
  364. data/lib/mongoid/validatable/uniqueness.rb +304 -0
  365. data/lib/mongoid/validatable.rb +163 -0
  366. data/lib/mongoid/version.rb +5 -0
  367. data/lib/mongoid/warnings.rb +30 -0
  368. data/lib/mongoid.rb +157 -0
  369. data/lib/rails/generators/mongoid/config/config_generator.rb +36 -0
  370. data/lib/rails/generators/mongoid/config/templates/mongoid.rb +24 -0
  371. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +137 -0
  372. data/lib/rails/generators/mongoid/model/model_generator.rb +25 -0
  373. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +19 -0
  374. data/lib/rails/generators/mongoid_generator.rb +29 -0
  375. data/lib/rails/mongoid.rb +27 -0
  376. data/spec/README.md +33 -0
  377. data/spec/config/mongoid.yml +70 -0
  378. data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
  379. data/spec/integration/app_spec.rb +377 -0
  380. data/spec/integration/associations/belongs_to_spec.rb +33 -0
  381. data/spec/integration/associations/embedded_dirty_spec.rb +57 -0
  382. data/spec/integration/associations/embedded_spec.rb +351 -0
  383. data/spec/integration/associations/embeds_many_spec.rb +219 -0
  384. data/spec/integration/associations/embeds_one_spec.rb +41 -0
  385. data/spec/integration/associations/foreign_key_spec.rb +107 -0
  386. data/spec/integration/associations/foreign_key_spec_models.rb +64 -0
  387. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  388. data/spec/integration/associations/has_many_spec.rb +128 -0
  389. data/spec/integration/associations/has_one_spec.rb +272 -0
  390. data/spec/integration/associations/nested_attributes_assignment_spec.rb +115 -0
  391. data/spec/integration/associations/reverse_population_spec.rb +34 -0
  392. data/spec/integration/associations/reverse_population_spec_models.rb +36 -0
  393. data/spec/integration/associations/scope_option_spec.rb +101 -0
  394. data/spec/integration/atomic/modifiers_spec.rb +116 -0
  395. data/spec/integration/bson_regexp_raw_spec.rb +19 -0
  396. data/spec/integration/callbacks_models.rb +155 -0
  397. data/spec/integration/callbacks_spec.rb +557 -0
  398. data/spec/integration/contextual/empty_spec.rb +141 -0
  399. data/spec/integration/criteria/alias_query_spec.rb +97 -0
  400. data/spec/integration/criteria/date_field_spec.rb +40 -0
  401. data/spec/integration/criteria/default_scope_spec.rb +72 -0
  402. data/spec/integration/criteria/logical_spec.rb +105 -0
  403. data/spec/integration/criteria/range_spec.rb +357 -0
  404. data/spec/integration/criteria/raw_value_spec.rb +525 -0
  405. data/spec/integration/criteria/time_with_zone_spec.rb +142 -0
  406. data/spec/integration/discriminator_key_spec.rb +391 -0
  407. data/spec/integration/discriminator_value_spec.rb +206 -0
  408. data/spec/integration/document_spec.rb +51 -0
  409. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  410. data/spec/integration/encryption_spec.rb +81 -0
  411. data/spec/integration/i18n_fallbacks_spec.rb +74 -0
  412. data/spec/integration/matcher_examples_spec.rb +765 -0
  413. data/spec/integration/matcher_operator_data/all.yml +140 -0
  414. data/spec/integration/matcher_operator_data/and.yml +93 -0
  415. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  416. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  417. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  418. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  419. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  420. data/spec/integration/matcher_operator_data/elem_match.yml +409 -0
  421. data/spec/integration/matcher_operator_data/elem_match_expr.yml +213 -0
  422. data/spec/integration/matcher_operator_data/eq.yml +191 -0
  423. data/spec/integration/matcher_operator_data/exists.yml +213 -0
  424. data/spec/integration/matcher_operator_data/generic_op.yml +17 -0
  425. data/spec/integration/matcher_operator_data/gt.yml +132 -0
  426. data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
  427. data/spec/integration/matcher_operator_data/gte.yml +132 -0
  428. data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
  429. data/spec/integration/matcher_operator_data/implicit.yml +331 -0
  430. data/spec/integration/matcher_operator_data/implicit_traversal.yml +112 -0
  431. data/spec/integration/matcher_operator_data/in.yml +210 -0
  432. data/spec/integration/matcher_operator_data/invalid_op.yml +59 -0
  433. data/spec/integration/matcher_operator_data/invalid_syntax.yml +39 -0
  434. data/spec/integration/matcher_operator_data/lt.yml +132 -0
  435. data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
  436. data/spec/integration/matcher_operator_data/lte.yml +132 -0
  437. data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
  438. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  439. data/spec/integration/matcher_operator_data/multiple.yml +29 -0
  440. data/spec/integration/matcher_operator_data/ne.yml +150 -0
  441. data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
  442. data/spec/integration/matcher_operator_data/nin.yml +114 -0
  443. data/spec/integration/matcher_operator_data/nor.yml +126 -0
  444. data/spec/integration/matcher_operator_data/not.yml +196 -0
  445. data/spec/integration/matcher_operator_data/or.yml +137 -0
  446. data/spec/integration/matcher_operator_data/regex.yml +174 -0
  447. data/spec/integration/matcher_operator_data/regex_options.yml +72 -0
  448. data/spec/integration/matcher_operator_data/size.yml +174 -0
  449. data/spec/integration/matcher_operator_data/type.yml +70 -0
  450. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  451. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  452. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  453. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  454. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  455. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  456. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  457. data/spec/integration/matcher_operator_data/type_decimal.yml +41 -0
  458. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  459. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  460. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  461. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  462. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  463. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  464. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  465. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  466. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  467. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  468. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  469. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  470. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  471. data/spec/integration/matcher_operator_spec.rb +122 -0
  472. data/spec/integration/matcher_spec.rb +237 -0
  473. data/spec/integration/persistence/range_field_spec.rb +350 -0
  474. data/spec/integration/server_query_spec.rb +141 -0
  475. data/spec/integration/shardable_spec.rb +148 -0
  476. data/spec/integration/stringified_symbol_field_spec.rb +203 -0
  477. data/spec/lite_spec_helper.rb +77 -0
  478. data/spec/mongoid/association/accessors_spec.rb +1049 -0
  479. data/spec/mongoid/association/auto_save_spec.rb +403 -0
  480. data/spec/mongoid/association/builders_spec.rb +255 -0
  481. data/spec/mongoid/association/constrainable_spec.rb +117 -0
  482. data/spec/mongoid/association/counter_cache_spec.rb +452 -0
  483. data/spec/mongoid/association/depending_spec.rb +959 -0
  484. data/spec/mongoid/association/eager_spec.rb +331 -0
  485. data/spec/mongoid/association/embedded/cyclic_spec.rb +180 -0
  486. data/spec/mongoid/association/embedded/dirty_spec.rb +67 -0
  487. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +174 -0
  488. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +90 -0
  489. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +646 -0
  490. data/spec/mongoid/association/embedded/embedded_in_spec.rb +914 -0
  491. data/spec/mongoid/association/embedded/embeds_many/binding_spec.rb +56 -0
  492. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +218 -0
  493. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +4858 -0
  494. data/spec/mongoid/association/embedded/embeds_many_models.rb +241 -0
  495. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +63 -0
  496. data/spec/mongoid/association/embedded/embeds_many_spec.rb +932 -0
  497. data/spec/mongoid/association/embedded/embeds_one/binding_spec.rb +79 -0
  498. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +106 -0
  499. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +1038 -0
  500. data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +8 -0
  501. data/spec/mongoid/association/embedded/embeds_one_models.rb +77 -0
  502. data/spec/mongoid/association/embedded/embeds_one_query_spec.rb +28 -0
  503. data/spec/mongoid/association/embedded/embeds_one_spec.rb +984 -0
  504. data/spec/mongoid/association/macros_spec.rb +1116 -0
  505. data/spec/mongoid/association/nested/many_spec.rb +232 -0
  506. data/spec/mongoid/association/nested/one_spec.rb +253 -0
  507. data/spec/mongoid/association/options_spec.rb +1323 -0
  508. data/spec/mongoid/association/polymorphic_spec.rb +162 -0
  509. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +244 -0
  510. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +292 -0
  511. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +412 -0
  512. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +1388 -0
  513. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  514. data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +57 -0
  515. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2030 -0
  516. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +180 -0
  517. data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +148 -0
  518. data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +196 -0
  519. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +76 -0
  520. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +3812 -0
  521. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +92 -0
  522. data/spec/mongoid/association/referenced/has_and_belongs_to_many_query_spec.rb +39 -0
  523. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +1104 -0
  524. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +155 -0
  525. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +251 -0
  526. data/spec/mongoid/association/referenced/has_many/eager_spec.rb +290 -0
  527. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2232 -0
  528. data/spec/mongoid/association/referenced/has_many/proxy_query_spec.rb +23 -0
  529. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +4118 -0
  530. data/spec/mongoid/association/referenced/has_many_models.rb +97 -0
  531. data/spec/mongoid/association/referenced/has_many_query_spec.rb +37 -0
  532. data/spec/mongoid/association/referenced/has_many_spec.rb +1273 -0
  533. data/spec/mongoid/association/referenced/has_one/binding_spec.rb +133 -0
  534. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +159 -0
  535. data/spec/mongoid/association/referenced/has_one/eager_spec.rb +193 -0
  536. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +1248 -0
  537. data/spec/mongoid/association/referenced/has_one_models.rb +113 -0
  538. data/spec/mongoid/association/referenced/has_one_query_spec.rb +37 -0
  539. data/spec/mongoid/association/referenced/has_one_spec.rb +1383 -0
  540. data/spec/mongoid/association/reflections_spec.rb +92 -0
  541. data/spec/mongoid/association/syncable_spec.rb +513 -0
  542. data/spec/mongoid/association_spec.rb +191 -0
  543. data/spec/mongoid/atomic/modifiers_spec.rb +505 -0
  544. data/spec/mongoid/atomic/paths/embedded/many_spec.rb +120 -0
  545. data/spec/mongoid/atomic/paths/embedded/one_spec.rb +112 -0
  546. data/spec/mongoid/atomic/paths/root_spec.rb +50 -0
  547. data/spec/mongoid/atomic/paths_spec.rb +350 -0
  548. data/spec/mongoid/atomic_spec.rb +412 -0
  549. data/spec/mongoid/attributes/dynamic_spec.rb +152 -0
  550. data/spec/mongoid/attributes/nested_spec.rb +5000 -0
  551. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  552. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  553. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  554. data/spec/mongoid/attributes/projector_spec.rb +40 -0
  555. data/spec/mongoid/attributes/readonly_spec.rb +271 -0
  556. data/spec/mongoid/attributes_spec.rb +2709 -0
  557. data/spec/mongoid/cacheable_spec.rb +114 -0
  558. data/spec/mongoid/changeable_spec.rb +2189 -0
  559. data/spec/mongoid/clients/factory_spec.rb +471 -0
  560. data/spec/mongoid/clients/options_spec.rb +521 -0
  561. data/spec/mongoid/clients/sessions_spec.rb +297 -0
  562. data/spec/mongoid/clients/transactions_spec.rb +1077 -0
  563. data/spec/mongoid/clients/transactions_spec_models.rb +114 -0
  564. data/spec/mongoid/clients_spec.rb +1218 -0
  565. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  566. data/spec/mongoid/composable_spec.rb +33 -0
  567. data/spec/mongoid/config/defaults_spec.rb +92 -0
  568. data/spec/mongoid/config/encryption_spec.rb +150 -0
  569. data/spec/mongoid/config/environment_spec.rb +175 -0
  570. data/spec/mongoid/config/introspection_spec.rb +113 -0
  571. data/spec/mongoid/config/options_spec.rb +75 -0
  572. data/spec/mongoid/config_spec.rb +861 -0
  573. data/spec/mongoid/contextual/aggregable/memory_spec.rb +573 -0
  574. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  575. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  576. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +595 -0
  577. data/spec/mongoid/contextual/aggregable/none_spec.rb +48 -0
  578. data/spec/mongoid/contextual/atomic_spec.rb +1142 -0
  579. data/spec/mongoid/contextual/geo_near_spec.rb +471 -0
  580. data/spec/mongoid/contextual/map_reduce_spec.rb +459 -0
  581. data/spec/mongoid/contextual/memory_spec.rb +2931 -0
  582. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +193 -0
  583. data/spec/mongoid/contextual/mongo_spec.rb +4534 -0
  584. data/spec/mongoid/contextual/none_spec.rb +170 -0
  585. data/spec/mongoid/copyable_spec.rb +1142 -0
  586. data/spec/mongoid/copyable_spec_models.rb +47 -0
  587. data/spec/mongoid/criteria/findable_spec.rb +1132 -0
  588. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  589. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  590. data/spec/mongoid/criteria/inspectable_spec.rb +29 -0
  591. data/spec/mongoid/criteria/marshalable_spec.rb +47 -0
  592. data/spec/mongoid/criteria/modifiable_spec.rb +1812 -0
  593. data/spec/mongoid/criteria/options_spec.rb +31 -0
  594. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +372 -0
  595. data/spec/mongoid/criteria/queryable/expandable_spec.rb +61 -0
  596. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +513 -0
  597. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +169 -0
  598. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +215 -0
  599. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +352 -0
  600. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +434 -0
  601. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +67 -0
  602. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +314 -0
  603. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +67 -0
  604. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +79 -0
  605. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +119 -0
  606. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +110 -0
  607. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +370 -0
  608. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +91 -0
  609. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +92 -0
  610. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +41 -0
  611. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +264 -0
  612. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +110 -0
  613. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +406 -0
  614. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +387 -0
  615. data/spec/mongoid/criteria/queryable/key_spec.rb +96 -0
  616. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +182 -0
  617. data/spec/mongoid/criteria/queryable/optional_spec.rb +1332 -0
  618. data/spec/mongoid/criteria/queryable/options_spec.rb +362 -0
  619. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +214 -0
  620. data/spec/mongoid/criteria/queryable/queryable_spec.rb +139 -0
  621. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +2538 -0
  622. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +38 -0
  623. data/spec/mongoid/criteria/queryable/selectable_spec.rb +2327 -0
  624. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +589 -0
  625. data/spec/mongoid/criteria/queryable/selector_spec.rb +990 -0
  626. data/spec/mongoid/criteria/queryable/smash_spec.rb +32 -0
  627. data/spec/mongoid/criteria/queryable/storable_spec.rb +203 -0
  628. data/spec/mongoid/criteria/scopable_spec.rb +601 -0
  629. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  630. data/spec/mongoid/criteria_projection_spec.rb +406 -0
  631. data/spec/mongoid/criteria_spec.rb +3238 -0
  632. data/spec/mongoid/document_fields_spec.rb +262 -0
  633. data/spec/mongoid/document_persistence_context_spec.rb +32 -0
  634. data/spec/mongoid/document_query_spec.rb +89 -0
  635. data/spec/mongoid/document_spec.rb +1365 -0
  636. data/spec/mongoid/equality_spec.rb +241 -0
  637. data/spec/mongoid/errors/ambiguous_relationship_spec.rb +31 -0
  638. data/spec/mongoid/errors/attribute_not_loaded_spec.rb +31 -0
  639. data/spec/mongoid/errors/callback_spec.rb +31 -0
  640. data/spec/mongoid/errors/delete_restriction_spec.rb +31 -0
  641. data/spec/mongoid/errors/document_not_destroyed_spec.rb +35 -0
  642. data/spec/mongoid/errors/document_not_found_spec.rb +182 -0
  643. data/spec/mongoid/errors/invalid_collection_spec.rb +38 -0
  644. data/spec/mongoid/errors/invalid_config_file_spec.rb +31 -0
  645. data/spec/mongoid/errors/invalid_config_option_spec.rb +31 -0
  646. data/spec/mongoid/errors/invalid_field_option_spec.rb +31 -0
  647. data/spec/mongoid/errors/invalid_field_spec.rb +39 -0
  648. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  649. data/spec/mongoid/errors/invalid_find_spec.rb +31 -0
  650. data/spec/mongoid/errors/invalid_includes_spec.rb +42 -0
  651. data/spec/mongoid/errors/invalid_index_spec.rb +31 -0
  652. data/spec/mongoid/errors/invalid_options_spec.rb +31 -0
  653. data/spec/mongoid/errors/invalid_path_spec.rb +25 -0
  654. data/spec/mongoid/errors/invalid_relation_spec.rb +39 -0
  655. data/spec/mongoid/errors/invalid_scope_spec.rb +31 -0
  656. data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +19 -0
  657. data/spec/mongoid/errors/invalid_storage_options_spec.rb +31 -0
  658. data/spec/mongoid/errors/invalid_time_spec.rb +31 -0
  659. data/spec/mongoid/errors/inverse_not_found_spec.rb +31 -0
  660. data/spec/mongoid/errors/mixed_client_configuration_spec.rb +31 -0
  661. data/spec/mongoid/errors/mixed_relations_spec.rb +31 -0
  662. data/spec/mongoid/errors/mongoid_error_spec.rb +83 -0
  663. data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +31 -0
  664. data/spec/mongoid/errors/no_client_config_spec.rb +31 -0
  665. data/spec/mongoid/errors/no_client_database_spec.rb +31 -0
  666. data/spec/mongoid/errors/no_client_hosts_spec.rb +31 -0
  667. data/spec/mongoid/errors/no_clients_config_spec.rb +31 -0
  668. data/spec/mongoid/errors/no_environment_spec.rb +31 -0
  669. data/spec/mongoid/errors/no_map_reduce_output_spec.rb +31 -0
  670. data/spec/mongoid/errors/no_metadata_spec.rb +25 -0
  671. data/spec/mongoid/errors/no_parent_spec.rb +31 -0
  672. data/spec/mongoid/errors/readonly_attribute_spec.rb +31 -0
  673. data/spec/mongoid/errors/readonly_document_spec.rb +31 -0
  674. data/spec/mongoid/errors/scope_overwrite_spec.rb +31 -0
  675. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +31 -0
  676. data/spec/mongoid/errors/unknown_attribute_spec.rb +31 -0
  677. data/spec/mongoid/errors/unsaved_document_spec.rb +39 -0
  678. data/spec/mongoid/errors/unsupported_javascript_spec.rb +31 -0
  679. data/spec/mongoid/errors/validations_spec.rb +47 -0
  680. data/spec/mongoid/extensions/array_spec.rb +620 -0
  681. data/spec/mongoid/extensions/big_decimal_spec.rb +908 -0
  682. data/spec/mongoid/extensions/binary_spec.rb +97 -0
  683. data/spec/mongoid/extensions/boolean_spec.rb +137 -0
  684. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +339 -0
  685. data/spec/mongoid/extensions/date_spec.rb +131 -0
  686. data/spec/mongoid/extensions/date_time_spec.rb +107 -0
  687. data/spec/mongoid/extensions/decimal128_spec.rb +46 -0
  688. data/spec/mongoid/extensions/false_class_spec.rb +44 -0
  689. data/spec/mongoid/extensions/float_spec.rb +140 -0
  690. data/spec/mongoid/extensions/hash_spec.rb +518 -0
  691. data/spec/mongoid/extensions/integer_spec.rb +135 -0
  692. data/spec/mongoid/extensions/module_spec.rb +44 -0
  693. data/spec/mongoid/extensions/nil_class_spec.rb +13 -0
  694. data/spec/mongoid/extensions/object_id_spec.rb +948 -0
  695. data/spec/mongoid/extensions/object_spec.rb +288 -0
  696. data/spec/mongoid/extensions/range_spec.rb +364 -0
  697. data/spec/mongoid/extensions/raw_value_spec.rb +66 -0
  698. data/spec/mongoid/extensions/regexp_spec.rb +97 -0
  699. data/spec/mongoid/extensions/set_spec.rb +141 -0
  700. data/spec/mongoid/extensions/string_spec.rb +387 -0
  701. data/spec/mongoid/extensions/stringified_symbol_spec.rb +84 -0
  702. data/spec/mongoid/extensions/symbol_spec.rb +71 -0
  703. data/spec/mongoid/extensions/time_spec.rb +706 -0
  704. data/spec/mongoid/extensions/time_with_zone_spec.rb +361 -0
  705. data/spec/mongoid/extensions/true_class_spec.rb +44 -0
  706. data/spec/mongoid/factory_spec.rb +534 -0
  707. data/spec/mongoid/fields/foreign_key_spec.rb +718 -0
  708. data/spec/mongoid/fields/localized_spec.rb +571 -0
  709. data/spec/mongoid/fields/standard_spec.rb +168 -0
  710. data/spec/mongoid/fields_spec.rb +2062 -0
  711. data/spec/mongoid/findable_spec.rb +929 -0
  712. data/spec/mongoid/indexable/specification_spec.rb +247 -0
  713. data/spec/mongoid/indexable_spec.rb +962 -0
  714. data/spec/mongoid/inspectable_spec.rb +86 -0
  715. data/spec/mongoid/interceptable_spec.rb +2373 -0
  716. data/spec/mongoid/interceptable_spec_models.rb +307 -0
  717. data/spec/mongoid/loading_spec.rb +109 -0
  718. data/spec/mongoid/loggable_spec.rb +23 -0
  719. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  720. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +239 -0
  721. data/spec/mongoid/matcher/extract_attribute_spec.rb +36 -0
  722. data/spec/mongoid/mongoizable_spec.rb +285 -0
  723. data/spec/mongoid/persistable/creatable_spec.rb +662 -0
  724. data/spec/mongoid/persistable/deletable_spec.rb +580 -0
  725. data/spec/mongoid/persistable/destroyable_spec.rb +652 -0
  726. data/spec/mongoid/persistable/incrementable_spec.rb +278 -0
  727. data/spec/mongoid/persistable/logical_spec.rb +196 -0
  728. data/spec/mongoid/persistable/maxable_spec.rb +146 -0
  729. data/spec/mongoid/persistable/minable_spec.rb +146 -0
  730. data/spec/mongoid/persistable/multipliable_spec.rb +226 -0
  731. data/spec/mongoid/persistable/poppable_spec.rb +167 -0
  732. data/spec/mongoid/persistable/pullable_spec.rb +330 -0
  733. data/spec/mongoid/persistable/pushable_spec.rb +425 -0
  734. data/spec/mongoid/persistable/renamable_spec.rb +187 -0
  735. data/spec/mongoid/persistable/savable_spec.rb +780 -0
  736. data/spec/mongoid/persistable/settable_spec.rb +581 -0
  737. data/spec/mongoid/persistable/unsettable_spec.rb +207 -0
  738. data/spec/mongoid/persistable/updatable_spec.rb +752 -0
  739. data/spec/mongoid/persistable/upsertable_spec.rb +228 -0
  740. data/spec/mongoid/persistable_spec.rb +321 -0
  741. data/spec/mongoid/persistence_context_spec.rb +695 -0
  742. data/spec/mongoid/positional_spec.rb +223 -0
  743. data/spec/mongoid/query_cache_middleware_spec.rb +50 -0
  744. data/spec/mongoid/query_cache_spec.rb +832 -0
  745. data/spec/mongoid/railties/console_sandbox_spec.rb +43 -0
  746. data/spec/mongoid/relations/proxy_spec.rb +126 -0
  747. data/spec/mongoid/reloadable_spec.rb +629 -0
  748. data/spec/mongoid/scopable_spec.rb +1312 -0
  749. data/spec/mongoid/selectable_spec.rb +136 -0
  750. data/spec/mongoid/serializable_spec.rb +942 -0
  751. data/spec/mongoid/shardable_models.rb +75 -0
  752. data/spec/mongoid/shardable_spec.rb +296 -0
  753. data/spec/mongoid/stateful_spec.rb +271 -0
  754. data/spec/mongoid/tasks/database_rake_spec.rb +370 -0
  755. data/spec/mongoid/tasks/database_spec.rb +308 -0
  756. data/spec/mongoid/tasks/encryption_spec.rb +147 -0
  757. data/spec/mongoid/threaded_spec.rb +343 -0
  758. data/spec/mongoid/timestamps/created/short_spec.rb +53 -0
  759. data/spec/mongoid/timestamps/created_spec.rb +46 -0
  760. data/spec/mongoid/timestamps/timeless_spec.rb +149 -0
  761. data/spec/mongoid/timestamps/updated/short_spec.rb +92 -0
  762. data/spec/mongoid/timestamps/updated_spec.rb +84 -0
  763. data/spec/mongoid/timestamps_spec.rb +498 -0
  764. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  765. data/spec/mongoid/touchable_spec.rb +1403 -0
  766. data/spec/mongoid/touchable_spec_models.rb +153 -0
  767. data/spec/mongoid/traversable_spec.rb +1395 -0
  768. data/spec/mongoid/validatable/associated_spec.rb +208 -0
  769. data/spec/mongoid/validatable/format_spec.rb +85 -0
  770. data/spec/mongoid/validatable/length_spec.rb +225 -0
  771. data/spec/mongoid/validatable/numericality_spec.rb +32 -0
  772. data/spec/mongoid/validatable/presence_spec.rb +592 -0
  773. data/spec/mongoid/validatable/uniqueness_spec.rb +2548 -0
  774. data/spec/mongoid/validatable_spec.rb +327 -0
  775. data/spec/mongoid/warnings_spec.rb +35 -0
  776. data/spec/mongoid_spec.rb +98 -0
  777. data/spec/rails/controller_extension/controller_runtime_spec.rb +112 -0
  778. data/spec/rails/mongoid_spec.rb +53 -0
  779. data/spec/shared/LICENSE +20 -0
  780. data/spec/shared/bin/get-mongodb-download-url +17 -0
  781. data/spec/shared/bin/s3-copy +45 -0
  782. data/spec/shared/bin/s3-upload +69 -0
  783. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  784. data/spec/shared/lib/mrss/cluster_config.rb +231 -0
  785. data/spec/shared/lib/mrss/constraints.rb +378 -0
  786. data/spec/shared/lib/mrss/docker_runner.rb +291 -0
  787. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  788. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  789. data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
  790. data/spec/shared/lib/mrss/server_version_registry.rb +120 -0
  791. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  792. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  793. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  794. data/spec/shared/lib/mrss/utils.rb +15 -0
  795. data/spec/shared/share/Dockerfile.erb +325 -0
  796. data/spec/shared/share/haproxy-1.conf +16 -0
  797. data/spec/shared/share/haproxy-2.conf +17 -0
  798. data/spec/shared/shlib/config.sh +27 -0
  799. data/spec/shared/shlib/distro.sh +74 -0
  800. data/spec/shared/shlib/server.sh +392 -0
  801. data/spec/shared/shlib/set_env.sh +169 -0
  802. data/spec/spec_helper.rb +210 -0
  803. data/spec/support/authorization.rb +15 -0
  804. data/spec/support/client_registry.rb +9 -0
  805. data/spec/support/constraints.rb +77 -0
  806. data/spec/support/crypt/models.rb +43 -0
  807. data/spec/support/crypt.rb +79 -0
  808. data/spec/support/expectations.rb +32 -0
  809. data/spec/support/feature_sandbox.rb +71 -0
  810. data/spec/support/helpers.rb +11 -0
  811. data/spec/support/immutable_ids.rb +118 -0
  812. data/spec/support/macros.rb +129 -0
  813. data/spec/support/models/account.rb +38 -0
  814. data/spec/support/models/acolyte.rb +19 -0
  815. data/spec/support/models/actor.rb +20 -0
  816. data/spec/support/models/actress.rb +4 -0
  817. data/spec/support/models/address.rb +87 -0
  818. data/spec/support/models/address_component.rb +7 -0
  819. data/spec/support/models/address_number.rb +8 -0
  820. data/spec/support/models/agency.rb +7 -0
  821. data/spec/support/models/agent.rb +18 -0
  822. data/spec/support/models/album.rb +20 -0
  823. data/spec/support/models/alert.rb +9 -0
  824. data/spec/support/models/animal.rb +28 -0
  825. data/spec/support/models/answer.rb +8 -0
  826. data/spec/support/models/appointment.rb +9 -0
  827. data/spec/support/models/armrest.rb +9 -0
  828. data/spec/support/models/array_field.rb +7 -0
  829. data/spec/support/models/article.rb +14 -0
  830. data/spec/support/models/artist.rb +90 -0
  831. data/spec/support/models/artwork.rb +6 -0
  832. data/spec/support/models/audible_sound.rb +3 -0
  833. data/spec/support/models/audio.rb +7 -0
  834. data/spec/support/models/augmentation.rb +25 -0
  835. data/spec/support/models/author.rb +8 -0
  836. data/spec/support/models/baby.rb +6 -0
  837. data/spec/support/models/band.rb +45 -0
  838. data/spec/support/models/bar.rb +12 -0
  839. data/spec/support/models/basic.rb +8 -0
  840. data/spec/support/models/bed.rb +3 -0
  841. data/spec/support/models/big_palette.rb +4 -0
  842. data/spec/support/models/birthday.rb +15 -0
  843. data/spec/support/models/bolt.rb +7 -0
  844. data/spec/support/models/bomb.rb +6 -0
  845. data/spec/support/models/book.rb +19 -0
  846. data/spec/support/models/breed.rb +6 -0
  847. data/spec/support/models/browser.rb +8 -0
  848. data/spec/support/models/building.rb +10 -0
  849. data/spec/support/models/building_address.rb +9 -0
  850. data/spec/support/models/bus.rb +9 -0
  851. data/spec/support/models/business.rb +7 -0
  852. data/spec/support/models/callback_test.rb +11 -0
  853. data/spec/support/models/canvas.rb +27 -0
  854. data/spec/support/models/car.rb +3 -0
  855. data/spec/support/models/cat.rb +10 -0
  856. data/spec/support/models/catalog.rb +24 -0
  857. data/spec/support/models/category.rb +10 -0
  858. data/spec/support/models/child.rb +6 -0
  859. data/spec/support/models/child_doc.rb +24 -0
  860. data/spec/support/models/church.rb +8 -0
  861. data/spec/support/models/circle.rb +5 -0
  862. data/spec/support/models/circuit.rb +6 -0
  863. data/spec/support/models/circus.rb +12 -0
  864. data/spec/support/models/code.rb +15 -0
  865. data/spec/support/models/coding/pull_request.rb +11 -0
  866. data/spec/support/models/coding.rb +3 -0
  867. data/spec/support/models/comment.rb +18 -0
  868. data/spec/support/models/company.rb +7 -0
  869. data/spec/support/models/consumption_period.rb +9 -0
  870. data/spec/support/models/contextable_item.rb +7 -0
  871. data/spec/support/models/contractor.rb +7 -0
  872. data/spec/support/models/cookie.rb +8 -0
  873. data/spec/support/models/country_code.rb +12 -0
  874. data/spec/support/models/courier_job.rb +6 -0
  875. data/spec/support/models/cover.rb +10 -0
  876. data/spec/support/models/crate.rb +12 -0
  877. data/spec/support/models/customer.rb +10 -0
  878. data/spec/support/models/customer_address.rb +11 -0
  879. data/spec/support/models/deed.rb +7 -0
  880. data/spec/support/models/definition.rb +11 -0
  881. data/spec/support/models/delegating_patient.rb +15 -0
  882. data/spec/support/models/description.rb +13 -0
  883. data/spec/support/models/dictionary.rb +18 -0
  884. data/spec/support/models/division.rb +12 -0
  885. data/spec/support/models/doctor.rb +14 -0
  886. data/spec/support/models/dog.rb +9 -0
  887. data/spec/support/models/dokument.rb +8 -0
  888. data/spec/support/models/draft.rb +11 -0
  889. data/spec/support/models/dragon.rb +6 -0
  890. data/spec/support/models/driver.rb +9 -0
  891. data/spec/support/models/drug.rb +8 -0
  892. data/spec/support/models/dungeon.rb +6 -0
  893. data/spec/support/models/edit.rb +7 -0
  894. data/spec/support/models/email.rb +8 -0
  895. data/spec/support/models/employer.rb +7 -0
  896. data/spec/support/models/entry.rb +8 -0
  897. data/spec/support/models/eraser.rb +3 -0
  898. data/spec/support/models/even.rb +9 -0
  899. data/spec/support/models/event.rb +24 -0
  900. data/spec/support/models/exhibition.rb +6 -0
  901. data/spec/support/models/exhibitor.rb +8 -0
  902. data/spec/support/models/explosion.rb +6 -0
  903. data/spec/support/models/eye.rb +11 -0
  904. data/spec/support/models/eye_bowl.rb +11 -0
  905. data/spec/support/models/face.rb +10 -0
  906. data/spec/support/models/fanatic.rb +8 -0
  907. data/spec/support/models/favorite.rb +14 -0
  908. data/spec/support/models/filesystem.rb +7 -0
  909. data/spec/support/models/fire_hydrant.rb +8 -0
  910. data/spec/support/models/firefox.rb +6 -0
  911. data/spec/support/models/fish.rb +9 -0
  912. data/spec/support/models/folder.rb +9 -0
  913. data/spec/support/models/folder_item.rb +11 -0
  914. data/spec/support/models/fruits.rb +36 -0
  915. data/spec/support/models/game.rb +21 -0
  916. data/spec/support/models/ghost.rb +9 -0
  917. data/spec/support/models/guitar.rb +4 -0
  918. data/spec/support/models/hole.rb +12 -0
  919. data/spec/support/models/home.rb +6 -0
  920. data/spec/support/models/house.rb +8 -0
  921. data/spec/support/models/html_writer.rb +5 -0
  922. data/spec/support/models/id_key.rb +8 -0
  923. data/spec/support/models/idnodef.rb +7 -0
  924. data/spec/support/models/image.rb +24 -0
  925. data/spec/support/models/implant.rb +27 -0
  926. data/spec/support/models/instrument.rb +8 -0
  927. data/spec/support/models/item.rb +10 -0
  928. data/spec/support/models/jar.rb +9 -0
  929. data/spec/support/models/kaleidoscope.rb +8 -0
  930. data/spec/support/models/kangaroo.rb +6 -0
  931. data/spec/support/models/label.rb +52 -0
  932. data/spec/support/models/language.rb +7 -0
  933. data/spec/support/models/lat_lng.rb +17 -0
  934. data/spec/support/models/league.rb +13 -0
  935. data/spec/support/models/learner.rb +4 -0
  936. data/spec/support/models/line_item.rb +8 -0
  937. data/spec/support/models/location.rb +10 -0
  938. data/spec/support/models/login.rb +10 -0
  939. data/spec/support/models/manufacturer.rb +9 -0
  940. data/spec/support/models/meat.rb +6 -0
  941. data/spec/support/models/membership.rb +7 -0
  942. data/spec/support/models/message.rb +13 -0
  943. data/spec/support/models/minim.rb +6 -0
  944. data/spec/support/models/mixed_drink.rb +6 -0
  945. data/spec/support/models/mop.rb +24 -0
  946. data/spec/support/models/movie.rb +15 -0
  947. data/spec/support/models/my_hash.rb +4 -0
  948. data/spec/support/models/name.rb +26 -0
  949. data/spec/support/models/name_only.rb +8 -0
  950. data/spec/support/models/node.rb +7 -0
  951. data/spec/support/models/note.rb +19 -0
  952. data/spec/support/models/nut.rb +7 -0
  953. data/spec/support/models/odd.rb +9 -0
  954. data/spec/support/models/order.rb +12 -0
  955. data/spec/support/models/ordered_post.rb +13 -0
  956. data/spec/support/models/ordered_preference.rb +8 -0
  957. data/spec/support/models/oscar.rb +16 -0
  958. data/spec/support/models/other_owner_object.rb +4 -0
  959. data/spec/support/models/override.rb +18 -0
  960. data/spec/support/models/ownable.rb +8 -0
  961. data/spec/support/models/owner.rb +10 -0
  962. data/spec/support/models/pack.rb +5 -0
  963. data/spec/support/models/page.rb +18 -0
  964. data/spec/support/models/page_question.rb +6 -0
  965. data/spec/support/models/palette.rb +9 -0
  966. data/spec/support/models/parent.rb +7 -0
  967. data/spec/support/models/parent_doc.rb +8 -0
  968. data/spec/support/models/passport.rb +22 -0
  969. data/spec/support/models/patient.rb +11 -0
  970. data/spec/support/models/pdf_writer.rb +5 -0
  971. data/spec/support/models/pencil.rb +3 -0
  972. data/spec/support/models/person.rb +231 -0
  973. data/spec/support/models/pet.rb +25 -0
  974. data/spec/support/models/pet_owner.rb +8 -0
  975. data/spec/support/models/phone.rb +13 -0
  976. data/spec/support/models/piano.rb +4 -0
  977. data/spec/support/models/pizza.rb +9 -0
  978. data/spec/support/models/player.rb +39 -0
  979. data/spec/support/models/post.rb +52 -0
  980. data/spec/support/models/post_genre.rb +8 -0
  981. data/spec/support/models/powerup.rb +25 -0
  982. data/spec/support/models/preference.rb +11 -0
  983. data/spec/support/models/princess.rb +12 -0
  984. data/spec/support/models/product.rb +20 -0
  985. data/spec/support/models/profile.rb +17 -0
  986. data/spec/support/models/pronunciation.rb +7 -0
  987. data/spec/support/models/pub.rb +8 -0
  988. data/spec/support/models/publication/encyclopedia.rb +11 -0
  989. data/spec/support/models/publication/review.rb +13 -0
  990. data/spec/support/models/publication.rb +4 -0
  991. data/spec/support/models/purchase.rb +6 -0
  992. data/spec/support/models/purchased_item.rb +10 -0
  993. data/spec/support/models/question.rb +10 -0
  994. data/spec/support/models/quiz.rb +9 -0
  995. data/spec/support/models/rating.rb +10 -0
  996. data/spec/support/models/record.rb +54 -0
  997. data/spec/support/models/registry.rb +7 -0
  998. data/spec/support/models/role.rb +9 -0
  999. data/spec/support/models/root_category.rb +6 -0
  1000. data/spec/support/models/sandbox/app/models/app_models_message.rb +3 -0
  1001. data/spec/support/models/sandbox/lib/models/lib_models_message.rb +3 -0
  1002. data/spec/support/models/sandbox/sandbox_message.rb +3 -0
  1003. data/spec/support/models/sandbox/sandbox_user.rb +3 -0
  1004. data/spec/support/models/sandbox/subdir/sandbox_comment.rb +3 -0
  1005. data/spec/support/models/sandwich.rb +11 -0
  1006. data/spec/support/models/scheduler.rb +9 -0
  1007. data/spec/support/models/school.rb +14 -0
  1008. data/spec/support/models/scribe.rb +7 -0
  1009. data/spec/support/models/sealer.rb +7 -0
  1010. data/spec/support/models/seat.rb +24 -0
  1011. data/spec/support/models/seo.rb +9 -0
  1012. data/spec/support/models/series.rb +7 -0
  1013. data/spec/support/models/server.rb +15 -0
  1014. data/spec/support/models/service.rb +24 -0
  1015. data/spec/support/models/shape.rb +14 -0
  1016. data/spec/support/models/shelf.rb +7 -0
  1017. data/spec/support/models/shield.rb +18 -0
  1018. data/spec/support/models/shipment_address.rb +5 -0
  1019. data/spec/support/models/shipping_container.rb +7 -0
  1020. data/spec/support/models/shipping_pack.rb +5 -0
  1021. data/spec/support/models/shirt.rb +11 -0
  1022. data/spec/support/models/shop.rb +8 -0
  1023. data/spec/support/models/short_agent.rb +6 -0
  1024. data/spec/support/models/short_quiz.rb +7 -0
  1025. data/spec/support/models/simple.rb +7 -0
  1026. data/spec/support/models/slave.rb +8 -0
  1027. data/spec/support/models/song.rb +10 -0
  1028. data/spec/support/models/sound.rb +7 -0
  1029. data/spec/support/models/spacer.rb +7 -0
  1030. data/spec/support/models/square.rb +6 -0
  1031. data/spec/support/models/staff.rb +9 -0
  1032. data/spec/support/models/store_as_dup_test1.rb +7 -0
  1033. data/spec/support/models/store_as_dup_test2.rb +7 -0
  1034. data/spec/support/models/store_as_dup_test3.rb +7 -0
  1035. data/spec/support/models/store_as_dup_test4.rb +7 -0
  1036. data/spec/support/models/strategy.rb +5 -0
  1037. data/spec/support/models/student.rb +14 -0
  1038. data/spec/support/models/sub_item.rb +5 -0
  1039. data/spec/support/models/subscription.rb +7 -0
  1040. data/spec/support/models/survey.rb +7 -0
  1041. data/spec/support/models/symptom.rb +8 -0
  1042. data/spec/support/models/system_role.rb +7 -0
  1043. data/spec/support/models/tag.rb +10 -0
  1044. data/spec/support/models/target.rb +7 -0
  1045. data/spec/support/models/template.rb +7 -0
  1046. data/spec/support/models/thing.rb +11 -0
  1047. data/spec/support/models/threadlocker.rb +7 -0
  1048. data/spec/support/models/title.rb +5 -0
  1049. data/spec/support/models/tool.rb +10 -0
  1050. data/spec/support/models/topping.rb +7 -0
  1051. data/spec/support/models/toy.rb +9 -0
  1052. data/spec/support/models/track.rb +40 -0
  1053. data/spec/support/models/translation.rb +7 -0
  1054. data/spec/support/models/tree.rb +11 -0
  1055. data/spec/support/models/truck.rb +7 -0
  1056. data/spec/support/models/updatable.rb +7 -0
  1057. data/spec/support/models/user.rb +23 -0
  1058. data/spec/support/models/user_account.rb +12 -0
  1059. data/spec/support/models/validation_callback.rb +12 -0
  1060. data/spec/support/models/vehicle.rb +18 -0
  1061. data/spec/support/models/version.rb +7 -0
  1062. data/spec/support/models/vertex.rb +8 -0
  1063. data/spec/support/models/vet_visit.rb +7 -0
  1064. data/spec/support/models/video.rb +15 -0
  1065. data/spec/support/models/video_game.rb +3 -0
  1066. data/spec/support/models/washer.rb +7 -0
  1067. data/spec/support/models/weapon.rb +25 -0
  1068. data/spec/support/models/wiki_page.rb +17 -0
  1069. data/spec/support/models/word.rb +17 -0
  1070. data/spec/support/models/word_origin.rb +13 -0
  1071. data/spec/support/models/writer.rb +13 -0
  1072. data/spec/support/rails_mock.rb +31 -0
  1073. data/spec/support/schema_maps/schema_map_aws.json +17 -0
  1074. data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  1075. data/spec/support/schema_maps/schema_map_azure.json +17 -0
  1076. data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
  1077. data/spec/support/schema_maps/schema_map_gcp.json +17 -0
  1078. data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
  1079. data/spec/support/schema_maps/schema_map_kmip.json +17 -0
  1080. data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
  1081. data/spec/support/schema_maps/schema_map_local.json +18 -0
  1082. data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
  1083. data/spec/support/shared/time.rb +40 -0
  1084. data/spec/support/sinatra_mock.rb +6 -0
  1085. data/spec/support/spec_config.rb +80 -0
  1086. metadata +1944 -0
@@ -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