ibm_db 3.0.5-x86-mingw32 → 4.0.0-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (586) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +4 -0
  3. data/LICENSE +1 -1
  4. data/MANIFEST +14 -14
  5. data/ParameterizedQueries README +6 -6
  6. data/README +208 -225
  7. data/ext/Makefile.nt32 +181 -181
  8. data/ext/Makefile.nt32.191 +212 -212
  9. data/ext/extconf.rb +291 -291
  10. data/ext/ibm_db.c +11887 -11887
  11. data/ext/ruby_ibm_db.h +241 -241
  12. data/ext/ruby_ibm_db_cli.c +866 -866
  13. data/ext/ruby_ibm_db_cli.h +500 -500
  14. data/init.rb +41 -41
  15. data/lib/IBM_DB.rb +27 -27
  16. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3452 -3177
  17. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +5 -2
  18. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  19. data/lib/mswin32/ibm_db.rb +91 -123
  20. data/lib/mswin32/rb2x/i386/ibm_db.so +0 -0
  21. data/test/active_record/connection_adapters/fake_adapter.rb +49 -46
  22. data/test/assets/example.log +1 -1
  23. data/test/assets/test.txt +1 -1
  24. data/test/cases/adapter_test.rb +351 -276
  25. data/test/cases/adapters/mysql2/active_schema_test.rb +193 -0
  26. data/test/cases/adapters/mysql2/bind_parameter_test.rb +50 -0
  27. data/test/cases/adapters/mysql2/boolean_test.rb +100 -0
  28. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +63 -0
  29. data/test/cases/adapters/mysql2/charset_collation_test.rb +54 -0
  30. data/test/cases/adapters/mysql2/connection_test.rb +210 -0
  31. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +45 -0
  32. data/test/cases/adapters/mysql2/enum_test.rb +26 -0
  33. data/test/cases/adapters/mysql2/explain_test.rb +21 -0
  34. data/test/cases/adapters/mysql2/json_test.rb +195 -0
  35. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +83 -0
  36. data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -0
  37. data/test/cases/adapters/mysql2/schema_migrations_test.rb +59 -0
  38. data/test/cases/adapters/mysql2/schema_test.rb +126 -0
  39. data/test/cases/adapters/mysql2/sp_test.rb +36 -0
  40. data/test/cases/adapters/mysql2/sql_types_test.rb +14 -0
  41. data/test/cases/adapters/mysql2/table_options_test.rb +42 -0
  42. data/test/cases/adapters/mysql2/unsigned_type_test.rb +66 -0
  43. data/test/cases/adapters/postgresql/active_schema_test.rb +98 -0
  44. data/test/cases/adapters/postgresql/array_test.rb +339 -0
  45. data/test/cases/adapters/postgresql/bit_string_test.rb +82 -0
  46. data/test/cases/adapters/postgresql/bytea_test.rb +134 -0
  47. data/test/cases/adapters/postgresql/case_insensitive_test.rb +26 -0
  48. data/test/cases/adapters/postgresql/change_schema_test.rb +38 -0
  49. data/test/cases/adapters/postgresql/cidr_test.rb +25 -0
  50. data/test/cases/adapters/postgresql/citext_test.rb +78 -0
  51. data/test/cases/adapters/postgresql/collation_test.rb +53 -0
  52. data/test/cases/adapters/postgresql/composite_test.rb +132 -0
  53. data/test/cases/adapters/postgresql/connection_test.rb +257 -0
  54. data/test/cases/adapters/postgresql/datatype_test.rb +92 -0
  55. data/test/cases/adapters/postgresql/domain_test.rb +47 -0
  56. data/test/cases/adapters/postgresql/enum_test.rb +91 -0
  57. data/test/cases/adapters/postgresql/explain_test.rb +20 -0
  58. data/test/cases/adapters/postgresql/extension_migration_test.rb +63 -0
  59. data/test/cases/adapters/postgresql/full_text_test.rb +44 -0
  60. data/test/cases/adapters/postgresql/geometric_test.rb +378 -0
  61. data/test/cases/adapters/postgresql/hstore_test.rb +382 -0
  62. data/test/cases/adapters/postgresql/infinity_test.rb +69 -0
  63. data/test/cases/adapters/postgresql/integer_test.rb +25 -0
  64. data/test/cases/adapters/postgresql/json_test.rb +237 -0
  65. data/test/cases/adapters/postgresql/ltree_test.rb +53 -0
  66. data/test/cases/adapters/postgresql/money_test.rb +96 -0
  67. data/test/cases/adapters/postgresql/network_test.rb +94 -0
  68. data/test/cases/adapters/postgresql/numbers_test.rb +49 -0
  69. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +405 -0
  70. data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -0
  71. data/test/cases/adapters/postgresql/quoting_test.rb +44 -0
  72. data/test/cases/adapters/postgresql/range_test.rb +343 -0
  73. data/test/cases/adapters/postgresql/referential_integrity_test.rb +111 -0
  74. data/test/cases/adapters/postgresql/rename_table_test.rb +34 -0
  75. data/test/cases/adapters/postgresql/schema_authorization_test.rb +119 -0
  76. data/test/cases/adapters/postgresql/schema_test.rb +597 -0
  77. data/test/cases/adapters/postgresql/serial_test.rb +154 -0
  78. data/test/cases/adapters/postgresql/statement_pool_test.rb +41 -0
  79. data/test/cases/adapters/postgresql/timestamp_test.rb +90 -0
  80. data/test/cases/adapters/postgresql/type_lookup_test.rb +33 -0
  81. data/test/cases/adapters/postgresql/utils_test.rb +62 -0
  82. data/test/cases/adapters/postgresql/uuid_test.rb +294 -0
  83. data/test/cases/adapters/postgresql/xml_test.rb +54 -0
  84. data/test/cases/adapters/sqlite3/collation_test.rb +53 -0
  85. data/test/cases/adapters/sqlite3/copy_table_test.rb +98 -0
  86. data/test/cases/adapters/sqlite3/explain_test.rb +21 -0
  87. data/test/cases/adapters/sqlite3/quoting_test.rb +101 -0
  88. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +441 -0
  89. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -0
  90. data/test/cases/adapters/sqlite3/statement_pool_test.rb +20 -0
  91. data/test/cases/aggregations_test.rb +168 -158
  92. data/test/cases/ar_schema_test.rb +146 -161
  93. data/test/cases/associations/association_scope_test.rb +16 -21
  94. data/test/cases/associations/belongs_to_associations_test.rb +1141 -1029
  95. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +41 -0
  96. data/test/cases/associations/callbacks_test.rb +190 -192
  97. data/test/cases/associations/cascaded_eager_loading_test.rb +188 -188
  98. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -36
  99. data/test/cases/associations/eager_load_nested_include_test.rb +126 -128
  100. data/test/cases/associations/eager_singularization_test.rb +148 -148
  101. data/test/cases/associations/eager_test.rb +1514 -1429
  102. data/test/cases/associations/extension_test.rb +87 -82
  103. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +1004 -972
  104. data/test/cases/associations/has_many_associations_test.rb +2501 -2182
  105. data/test/cases/associations/has_many_through_associations_test.rb +1271 -1204
  106. data/test/cases/associations/has_one_associations_test.rb +707 -610
  107. data/test/cases/associations/has_one_through_associations_test.rb +383 -380
  108. data/test/cases/associations/inner_join_association_test.rb +139 -139
  109. data/test/cases/associations/inverse_associations_test.rb +733 -706
  110. data/test/cases/associations/join_model_test.rb +777 -754
  111. data/test/cases/associations/left_outer_join_association_test.rb +88 -0
  112. data/test/cases/associations/nested_through_associations_test.rb +579 -579
  113. data/test/cases/associations/required_test.rb +102 -82
  114. data/test/cases/associations_test.rb +385 -380
  115. data/test/cases/attribute_decorators_test.rb +125 -125
  116. data/test/cases/attribute_methods/read_test.rb +60 -60
  117. data/test/cases/attribute_methods_test.rb +1009 -952
  118. data/test/cases/attribute_set_test.rb +270 -210
  119. data/test/cases/attribute_test.rb +246 -180
  120. data/test/cases/attributes_test.rb +253 -136
  121. data/test/cases/autosave_association_test.rb +1708 -1595
  122. data/test/cases/base_test.rb +1713 -1664
  123. data/test/cases/batches_test.rb +489 -212
  124. data/test/cases/binary_test.rb +44 -52
  125. data/test/cases/bind_parameter_test.rb +110 -100
  126. data/test/cases/cache_key_test.rb +25 -0
  127. data/test/cases/calculations_test.rb +798 -646
  128. data/test/cases/callbacks_test.rb +636 -543
  129. data/test/cases/clone_test.rb +40 -40
  130. data/test/cases/coders/json_test.rb +15 -0
  131. data/test/cases/coders/yaml_column_test.rb +63 -63
  132. data/test/cases/collection_cache_key_test.rb +115 -0
  133. data/test/cases/column_alias_test.rb +17 -17
  134. data/test/cases/column_definition_test.rb +92 -123
  135. data/test/cases/comment_test.rb +143 -0
  136. data/test/cases/connection_adapters/adapter_leasing_test.rb +56 -54
  137. data/test/cases/connection_adapters/connection_handler_test.rb +160 -53
  138. data/test/cases/connection_adapters/connection_specification_test.rb +12 -12
  139. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +255 -293
  140. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +69 -65
  141. data/test/cases/connection_adapters/quoting_test.rb +13 -13
  142. data/test/cases/connection_adapters/schema_cache_test.rb +61 -56
  143. data/test/cases/connection_adapters/type_lookup_test.rb +118 -110
  144. data/test/cases/connection_management_test.rb +112 -122
  145. data/test/cases/connection_pool_test.rb +521 -346
  146. data/test/cases/connection_specification/resolver_test.rb +131 -116
  147. data/test/cases/core_test.rb +112 -112
  148. data/test/cases/counter_cache_test.rb +214 -209
  149. data/test/cases/custom_locking_test.rb +17 -17
  150. data/test/cases/database_statements_test.rb +34 -19
  151. data/test/cases/{invalid_date_test.rb → date_test.rb} +44 -32
  152. data/test/cases/date_time_precision_test.rb +106 -0
  153. data/test/cases/date_time_test.rb +61 -61
  154. data/test/cases/defaults_test.rb +218 -223
  155. data/test/cases/dirty_test.rb +763 -785
  156. data/test/cases/disconnected_test.rb +30 -28
  157. data/test/cases/dup_test.rb +157 -157
  158. data/test/cases/enum_test.rb +444 -290
  159. data/test/cases/errors_test.rb +16 -0
  160. data/test/cases/explain_subscriber_test.rb +64 -64
  161. data/test/cases/explain_test.rb +87 -76
  162. data/test/cases/finder_respond_to_test.rb +60 -60
  163. data/test/cases/finder_test.rb +1294 -1169
  164. data/test/cases/fixture_set/file_test.rb +156 -138
  165. data/test/cases/fixtures_test.rb +988 -908
  166. data/test/cases/forbidden_attributes_protection_test.rb +165 -99
  167. data/test/cases/habtm_destroy_order_test.rb +61 -61
  168. data/test/cases/helper.rb +204 -210
  169. data/test/cases/hot_compatibility_test.rb +142 -54
  170. data/test/cases/i18n_test.rb +45 -45
  171. data/test/cases/inheritance_test.rb +606 -375
  172. data/test/cases/integration_test.rb +155 -139
  173. data/test/cases/invalid_connection_test.rb +24 -22
  174. data/test/cases/invertible_migration_test.rb +387 -295
  175. data/test/cases/json_serialization_test.rb +311 -302
  176. data/test/cases/locking_test.rb +493 -477
  177. data/test/cases/log_subscriber_test.rb +225 -136
  178. data/test/cases/migration/change_schema_test.rb +458 -512
  179. data/test/cases/migration/change_table_test.rb +256 -224
  180. data/test/cases/migration/column_attributes_test.rb +176 -192
  181. data/test/cases/migration/column_positioning_test.rb +56 -56
  182. data/test/cases/migration/columns_test.rb +310 -304
  183. data/test/cases/migration/command_recorder_test.rb +350 -305
  184. data/test/cases/migration/compatibility_test.rb +118 -0
  185. data/test/cases/migration/create_join_table_test.rb +157 -148
  186. data/test/cases/migration/foreign_key_test.rb +360 -328
  187. data/test/cases/migration/helper.rb +39 -39
  188. data/test/cases/migration/index_test.rb +218 -216
  189. data/test/cases/migration/logger_test.rb +36 -36
  190. data/test/cases/migration/pending_migrations_test.rb +52 -53
  191. data/test/cases/migration/references_foreign_key_test.rb +216 -169
  192. data/test/cases/migration/references_index_test.rb +101 -101
  193. data/test/cases/migration/references_statements_test.rb +136 -116
  194. data/test/cases/migration/rename_table_test.rb +93 -93
  195. data/test/cases/migration_test.rb +1157 -959
  196. data/test/cases/migrator_test.rb +470 -388
  197. data/test/cases/mixin_test.rb +68 -70
  198. data/test/cases/modules_test.rb +172 -173
  199. data/test/cases/multiparameter_attributes_test.rb +372 -350
  200. data/test/cases/multiple_db_test.rb +122 -115
  201. data/test/cases/nested_attributes_test.rb +1098 -1070
  202. data/test/cases/nested_attributes_with_callbacks_test.rb +144 -144
  203. data/test/cases/persistence_test.rb +1001 -909
  204. data/test/cases/pooled_connections_test.rb +81 -81
  205. data/test/cases/primary_keys_test.rb +376 -237
  206. data/test/cases/query_cache_test.rb +446 -326
  207. data/test/cases/quoting_test.rb +202 -156
  208. data/test/cases/readonly_test.rb +119 -118
  209. data/test/cases/reaper_test.rb +85 -85
  210. data/test/cases/reflection_test.rb +509 -463
  211. data/test/cases/relation/delegation_test.rb +63 -68
  212. data/test/cases/relation/merging_test.rb +157 -161
  213. data/test/cases/relation/mutation_test.rb +183 -165
  214. data/test/cases/relation/or_test.rb +92 -0
  215. data/test/cases/relation/predicate_builder_test.rb +16 -14
  216. data/test/cases/relation/record_fetch_warning_test.rb +40 -0
  217. data/test/cases/relation/where_chain_test.rb +105 -181
  218. data/test/cases/relation/where_clause_test.rb +182 -0
  219. data/test/cases/relation/where_test.rb +322 -300
  220. data/test/cases/relation_test.rb +328 -319
  221. data/test/cases/relations_test.rb +2026 -1815
  222. data/test/cases/reload_models_test.rb +22 -22
  223. data/test/cases/result_test.rb +90 -80
  224. data/test/cases/sanitize_test.rb +176 -83
  225. data/test/cases/schema_dumper_test.rb +457 -463
  226. data/test/cases/schema_loading_test.rb +52 -0
  227. data/test/cases/scoping/default_scoping_test.rb +528 -454
  228. data/test/cases/scoping/named_scoping_test.rb +561 -524
  229. data/test/cases/scoping/relation_scoping_test.rb +400 -357
  230. data/test/cases/secure_token_test.rb +32 -0
  231. data/test/cases/serialization_test.rb +104 -104
  232. data/test/cases/serialized_attribute_test.rb +364 -277
  233. data/test/cases/statement_cache_test.rb +136 -98
  234. data/test/cases/store_test.rb +195 -194
  235. data/test/cases/suppressor_test.rb +63 -0
  236. data/test/cases/tasks/database_tasks_test.rb +462 -398
  237. data/test/cases/tasks/mysql_rake_test.rb +345 -324
  238. data/test/cases/tasks/postgresql_rake_test.rb +304 -250
  239. data/test/cases/tasks/sqlite_rake_test.rb +220 -193
  240. data/test/cases/test_case.rb +131 -123
  241. data/test/cases/test_fixtures_test.rb +36 -0
  242. data/test/cases/time_precision_test.rb +102 -0
  243. data/test/cases/timestamp_test.rb +501 -467
  244. data/test/cases/touch_later_test.rb +121 -0
  245. data/test/cases/transaction_callbacks_test.rb +518 -452
  246. data/test/cases/transaction_isolation_test.rb +106 -106
  247. data/test/cases/transactions_test.rb +834 -817
  248. data/test/cases/type/adapter_specific_registry_test.rb +133 -0
  249. data/test/cases/type/date_time_test.rb +14 -0
  250. data/test/cases/type/integer_test.rb +27 -121
  251. data/test/cases/type/string_test.rb +22 -36
  252. data/test/cases/type/type_map_test.rb +177 -177
  253. data/test/cases/type_test.rb +39 -0
  254. data/test/cases/types_test.rb +24 -141
  255. data/test/cases/unconnected_test.rb +33 -33
  256. data/test/cases/validations/absence_validation_test.rb +73 -0
  257. data/test/cases/validations/association_validation_test.rb +97 -86
  258. data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -84
  259. data/test/cases/validations/i18n_validation_test.rb +86 -90
  260. data/test/cases/validations/length_validation_test.rb +79 -47
  261. data/test/cases/validations/presence_validation_test.rb +103 -68
  262. data/test/cases/validations/uniqueness_validation_test.rb +548 -457
  263. data/test/cases/validations_repair_helper.rb +19 -23
  264. data/test/cases/validations_test.rb +194 -165
  265. data/test/cases/view_test.rb +216 -119
  266. data/test/cases/yaml_serialization_test.rb +121 -126
  267. data/test/config.example.yml +97 -0
  268. data/test/config.rb +5 -5
  269. data/test/fixtures/accounts.yml +29 -29
  270. data/test/fixtures/admin/accounts.yml +2 -2
  271. data/test/fixtures/admin/users.yml +10 -10
  272. data/test/fixtures/author_addresses.original +11 -0
  273. data/test/fixtures/author_addresses.yml +17 -17
  274. data/test/fixtures/author_favorites.yml +3 -3
  275. data/test/fixtures/authors.original +17 -0
  276. data/test/fixtures/authors.yml +23 -23
  277. data/test/fixtures/bad_posts.yml +9 -0
  278. data/test/fixtures/binaries.yml +133 -133
  279. data/test/fixtures/books.yml +31 -11
  280. data/test/fixtures/bulbs.yml +5 -5
  281. data/test/fixtures/cars.yml +9 -9
  282. data/test/fixtures/categories.yml +19 -19
  283. data/test/fixtures/categories/special_categories.yml +9 -9
  284. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -4
  285. data/test/fixtures/categories_ordered.yml +7 -7
  286. data/test/fixtures/categories_posts.yml +31 -31
  287. data/test/fixtures/categorizations.yml +23 -23
  288. data/test/fixtures/clubs.yml +8 -8
  289. data/test/fixtures/collections.yml +3 -3
  290. data/test/fixtures/colleges.yml +3 -3
  291. data/test/fixtures/comments.yml +65 -65
  292. data/test/fixtures/companies.yml +67 -67
  293. data/test/fixtures/computers.yml +10 -10
  294. data/test/fixtures/content.yml +3 -0
  295. data/test/fixtures/content_positions.yml +3 -0
  296. data/test/fixtures/courses.yml +8 -8
  297. data/test/fixtures/customers.yml +25 -25
  298. data/test/fixtures/dashboards.yml +6 -6
  299. data/test/fixtures/dead_parrots.yml +5 -0
  300. data/test/fixtures/developers.yml +22 -22
  301. data/test/fixtures/developers_projects.yml +16 -16
  302. data/test/fixtures/dog_lovers.yml +7 -7
  303. data/test/fixtures/dogs.yml +4 -4
  304. data/test/fixtures/doubloons.yml +3 -3
  305. data/test/fixtures/edges.yml +5 -5
  306. data/test/fixtures/entrants.yml +14 -14
  307. data/test/fixtures/essays.yml +6 -6
  308. data/test/fixtures/faces.yml +11 -11
  309. data/test/fixtures/fk_test_has_fk.yml +3 -3
  310. data/test/fixtures/fk_test_has_pk.yml +1 -1
  311. data/test/fixtures/friendships.yml +4 -4
  312. data/test/fixtures/funny_jokes.yml +10 -10
  313. data/test/fixtures/interests.yml +33 -33
  314. data/test/fixtures/items.yml +3 -3
  315. data/test/fixtures/jobs.yml +7 -7
  316. data/test/fixtures/legacy_things.yml +3 -3
  317. data/test/fixtures/live_parrots.yml +4 -0
  318. data/test/fixtures/mateys.yml +4 -4
  319. data/test/fixtures/member_details.yml +8 -8
  320. data/test/fixtures/member_types.yml +6 -6
  321. data/test/fixtures/members.yml +11 -11
  322. data/test/fixtures/memberships.yml +34 -34
  323. data/test/fixtures/men.yml +5 -5
  324. data/test/fixtures/minimalistics.yml +2 -2
  325. data/test/fixtures/minivans.yml +5 -5
  326. data/test/fixtures/mixed_case_monkeys.yml +6 -6
  327. data/test/fixtures/mixins.yml +29 -29
  328. data/test/fixtures/movies.yml +7 -7
  329. data/test/fixtures/naked/yml/accounts.yml +1 -1
  330. data/test/fixtures/naked/yml/companies.yml +1 -1
  331. data/test/fixtures/naked/yml/courses.yml +1 -1
  332. data/test/fixtures/naked/yml/parrots.yml +2 -0
  333. data/test/fixtures/naked/yml/trees.yml +3 -0
  334. data/test/fixtures/nodes.yml +29 -0
  335. data/test/fixtures/organizations.yml +5 -5
  336. data/test/fixtures/other_comments.yml +6 -0
  337. data/test/fixtures/other_dogs.yml +2 -0
  338. data/test/fixtures/other_posts.yml +7 -0
  339. data/test/fixtures/other_topics.yml +42 -42
  340. data/test/fixtures/owners.yml +9 -9
  341. data/test/fixtures/parrots.yml +27 -27
  342. data/test/fixtures/parrots_pirates.yml +7 -7
  343. data/test/fixtures/people.yml +24 -24
  344. data/test/fixtures/peoples_treasures.yml +3 -3
  345. data/test/fixtures/pets.yml +19 -19
  346. data/test/fixtures/pirates.yml +15 -12
  347. data/test/fixtures/posts.yml +80 -80
  348. data/test/fixtures/price_estimates.yml +16 -7
  349. data/test/fixtures/products.yml +4 -4
  350. data/test/fixtures/projects.yml +7 -7
  351. data/test/fixtures/ratings.yml +14 -14
  352. data/test/fixtures/readers.yml +11 -11
  353. data/test/fixtures/references.yml +17 -17
  354. data/test/fixtures/reserved_words/distinct.yml +5 -5
  355. data/test/fixtures/reserved_words/distinct_select.yml +11 -11
  356. data/test/fixtures/reserved_words/group.yml +14 -14
  357. data/test/fixtures/reserved_words/select.yml +8 -8
  358. data/test/fixtures/reserved_words/values.yml +7 -7
  359. data/test/fixtures/ships.yml +6 -6
  360. data/test/fixtures/speedometers.yml +8 -8
  361. data/test/fixtures/sponsors.yml +12 -12
  362. data/test/fixtures/string_key_objects.yml +7 -7
  363. data/test/fixtures/subscribers.yml +10 -10
  364. data/test/fixtures/subscriptions.yml +12 -12
  365. data/test/fixtures/taggings.yml +78 -78
  366. data/test/fixtures/tags.yml +11 -11
  367. data/test/fixtures/tasks.yml +7 -7
  368. data/test/fixtures/teapots.yml +3 -3
  369. data/test/fixtures/to_be_linked/accounts.yml +2 -2
  370. data/test/fixtures/to_be_linked/users.yml +10 -10
  371. data/test/fixtures/topics.yml +49 -49
  372. data/test/fixtures/toys.yml +14 -14
  373. data/test/fixtures/traffic_lights.yml +9 -9
  374. data/test/fixtures/treasures.yml +10 -10
  375. data/test/fixtures/trees.yml +3 -0
  376. data/test/fixtures/uuid_children.yml +3 -3
  377. data/test/fixtures/uuid_parents.yml +2 -2
  378. data/test/fixtures/variants.yml +4 -4
  379. data/test/fixtures/vegetables.yml +19 -19
  380. data/test/fixtures/vertices.yml +3 -3
  381. data/test/fixtures/warehouse_things.yml +2 -2
  382. data/test/fixtures/zines.yml +5 -5
  383. data/test/migrations/10_urban/9_add_expressions.rb +11 -11
  384. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -15
  385. data/test/migrations/magic/1_currencies_have_symbols.rb +12 -12
  386. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -9
  387. data/test/migrations/missing/1_people_have_last_names.rb +9 -9
  388. data/test/migrations/missing/3_we_need_reminders.rb +12 -12
  389. data/test/migrations/missing/4_innocent_jointable.rb +12 -12
  390. data/test/migrations/rename/1_we_need_things.rb +11 -11
  391. data/test/migrations/rename/2_rename_things.rb +9 -9
  392. data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -9
  393. data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -9
  394. data/test/migrations/to_copy2/1_create_articles.rb +7 -7
  395. data/test/migrations/to_copy2/2_create_comments.rb +7 -7
  396. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -9
  397. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -9
  398. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -9
  399. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -7
  400. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -7
  401. data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -9
  402. data/test/migrations/valid/2_we_need_reminders.rb +12 -12
  403. data/test/migrations/valid/3_innocent_jointable.rb +12 -12
  404. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -9
  405. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +12 -12
  406. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +12 -12
  407. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -9
  408. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -12
  409. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -12
  410. data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -8
  411. data/test/models/admin.rb +5 -5
  412. data/test/models/admin/account.rb +3 -3
  413. data/test/models/admin/randomly_named_c1.rb +6 -2
  414. data/test/models/admin/user.rb +40 -40
  415. data/test/models/aircraft.rb +5 -4
  416. data/test/models/arunit2_model.rb +3 -3
  417. data/test/models/author.rb +209 -212
  418. data/test/models/auto_id.rb +4 -4
  419. data/test/models/autoloadable/extra_firm.rb +2 -2
  420. data/test/models/binary.rb +2 -2
  421. data/test/models/bird.rb +12 -12
  422. data/test/models/book.rb +23 -18
  423. data/test/models/boolean.rb +2 -2
  424. data/test/models/bulb.rb +52 -51
  425. data/test/models/cake_designer.rb +3 -3
  426. data/test/models/car.rb +29 -26
  427. data/test/models/carrier.rb +2 -2
  428. data/test/models/cat.rb +10 -0
  429. data/test/models/categorization.rb +19 -19
  430. data/test/models/category.rb +35 -35
  431. data/test/models/chef.rb +8 -7
  432. data/test/models/citation.rb +3 -3
  433. data/test/models/club.rb +25 -23
  434. data/test/models/college.rb +10 -10
  435. data/test/models/column.rb +3 -3
  436. data/test/models/column_name.rb +3 -3
  437. data/test/models/comment.rb +76 -64
  438. data/test/models/company.rb +230 -228
  439. data/test/models/company_in_module.rb +98 -98
  440. data/test/models/computer.rb +3 -3
  441. data/test/models/contact.rb +41 -41
  442. data/test/models/content.rb +40 -0
  443. data/test/models/contract.rb +20 -20
  444. data/test/models/country.rb +7 -7
  445. data/test/models/course.rb +6 -6
  446. data/test/models/customer.rb +83 -77
  447. data/test/models/customer_carrier.rb +14 -14
  448. data/test/models/dashboard.rb +3 -3
  449. data/test/models/default.rb +2 -2
  450. data/test/models/department.rb +4 -4
  451. data/test/models/developer.rb +274 -255
  452. data/test/models/dog.rb +5 -5
  453. data/test/models/dog_lover.rb +5 -5
  454. data/test/models/doubloon.rb +12 -12
  455. data/test/models/drink_designer.rb +3 -3
  456. data/test/models/edge.rb +5 -5
  457. data/test/models/electron.rb +5 -5
  458. data/test/models/engine.rb +4 -4
  459. data/test/models/entrant.rb +3 -3
  460. data/test/models/essay.rb +5 -5
  461. data/test/models/event.rb +3 -3
  462. data/test/models/eye.rb +37 -37
  463. data/test/models/face.rb +9 -9
  464. data/test/models/friendship.rb +6 -6
  465. data/test/models/guid.rb +2 -2
  466. data/test/models/guitar.rb +4 -0
  467. data/test/models/hotel.rb +11 -9
  468. data/test/models/image.rb +3 -3
  469. data/test/models/interest.rb +5 -5
  470. data/test/models/invoice.rb +4 -4
  471. data/test/models/item.rb +7 -7
  472. data/test/models/job.rb +7 -7
  473. data/test/models/joke.rb +7 -7
  474. data/test/models/keyboard.rb +3 -3
  475. data/test/models/legacy_thing.rb +3 -3
  476. data/test/models/lesson.rb +11 -11
  477. data/test/models/line_item.rb +3 -3
  478. data/test/models/liquid.rb +4 -4
  479. data/test/models/man.rb +11 -11
  480. data/test/models/matey.rb +4 -4
  481. data/test/models/member.rb +42 -41
  482. data/test/models/member_detail.rb +8 -7
  483. data/test/models/member_type.rb +3 -3
  484. data/test/models/membership.rb +35 -35
  485. data/test/models/mentor.rb +3 -0
  486. data/test/models/minimalistic.rb +2 -2
  487. data/test/models/minivan.rb +9 -9
  488. data/test/models/mixed_case_monkey.rb +3 -3
  489. data/test/models/mocktail_designer.rb +2 -0
  490. data/test/models/molecule.rb +6 -6
  491. data/test/models/movie.rb +5 -5
  492. data/test/models/node.rb +5 -0
  493. data/test/models/non_primary_key.rb +2 -0
  494. data/test/models/notification.rb +3 -0
  495. data/test/models/order.rb +4 -4
  496. data/test/models/organization.rb +14 -14
  497. data/test/models/other_dog.rb +5 -0
  498. data/test/models/owner.rb +37 -34
  499. data/test/models/parrot.rb +28 -29
  500. data/test/models/person.rb +142 -143
  501. data/test/models/personal_legacy_thing.rb +4 -4
  502. data/test/models/pet.rb +18 -15
  503. data/test/models/pet_treasure.rb +6 -0
  504. data/test/models/pirate.rb +92 -92
  505. data/test/models/possession.rb +3 -3
  506. data/test/models/post.rb +273 -264
  507. data/test/models/price_estimate.rb +4 -4
  508. data/test/models/professor.rb +5 -5
  509. data/test/models/project.rb +40 -31
  510. data/test/models/publisher.rb +2 -2
  511. data/test/models/publisher/article.rb +4 -4
  512. data/test/models/publisher/magazine.rb +3 -3
  513. data/test/models/randomly_named_c1.rb +1 -1
  514. data/test/models/rating.rb +4 -4
  515. data/test/models/reader.rb +23 -23
  516. data/test/models/recipe.rb +3 -0
  517. data/test/models/record.rb +2 -2
  518. data/test/models/reference.rb +22 -22
  519. data/test/models/reply.rb +61 -61
  520. data/test/models/ship.rb +39 -33
  521. data/test/models/ship_part.rb +8 -8
  522. data/test/models/shop.rb +17 -17
  523. data/test/models/shop_account.rb +6 -6
  524. data/test/models/speedometer.rb +6 -6
  525. data/test/models/sponsor.rb +7 -7
  526. data/test/models/string_key_object.rb +3 -3
  527. data/test/models/student.rb +4 -4
  528. data/test/models/subject.rb +16 -16
  529. data/test/models/subscriber.rb +8 -8
  530. data/test/models/subscription.rb +4 -4
  531. data/test/models/tag.rb +13 -7
  532. data/test/models/tagging.rb +13 -13
  533. data/test/models/task.rb +5 -5
  534. data/test/models/topic.rb +118 -124
  535. data/test/models/toy.rb +6 -6
  536. data/test/models/traffic_light.rb +4 -4
  537. data/test/models/treasure.rb +14 -14
  538. data/test/models/treaty.rb +7 -7
  539. data/test/models/tree.rb +3 -0
  540. data/test/models/tuning_peg.rb +4 -0
  541. data/test/models/tyre.rb +11 -11
  542. data/test/models/user.rb +14 -0
  543. data/test/models/uuid_child.rb +3 -3
  544. data/test/models/uuid_item.rb +6 -0
  545. data/test/models/uuid_parent.rb +3 -3
  546. data/test/models/vegetables.rb +24 -24
  547. data/test/models/vehicle.rb +6 -6
  548. data/test/models/vertex.rb +9 -9
  549. data/test/models/warehouse_thing.rb +5 -5
  550. data/test/models/wheel.rb +3 -3
  551. data/test/models/without_table.rb +3 -3
  552. data/test/models/zine.rb +3 -3
  553. data/test/schema/mysql2_specific_schema.rb +68 -58
  554. data/test/schema/oracle_specific_schema.rb +40 -43
  555. data/test/schema/postgresql_specific_schema.rb +114 -202
  556. data/test/schema/schema.rb +1057 -952
  557. data/test/schema/schema.rb.original +1057 -0
  558. data/test/schema/sqlite_specific_schema.rb +18 -22
  559. data/test/support/config.rb +43 -43
  560. data/test/support/connection.rb +23 -22
  561. data/test/support/connection_helper.rb +14 -14
  562. data/test/support/ddl_helper.rb +8 -8
  563. data/test/support/schema_dumping_helper.rb +20 -20
  564. data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -0
  565. data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -0
  566. metadata +129 -28
  567. data/lib/mswin32/rb19x/ibm_db.so +0 -0
  568. data/lib/mswin32/rb21x/i386/ibm_db.so +0 -0
  569. data/lib/mswin32/rb22x/i386/ibm_db.so +0 -0
  570. data/lib/mswin32/rb23x/i386/ibm_db.so +0 -0
  571. data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +0 -26
  572. data/test/cases/attribute_methods/serialization_test.rb +0 -29
  573. data/test/cases/migration/change_schema_test - Copy.rb +0 -448
  574. data/test/cases/migration/foreign_key_test - Changed.rb +0 -325
  575. data/test/cases/migration/table_and_index_test.rb +0 -24
  576. data/test/cases/relation/where_test2.rb +0 -36
  577. data/test/cases/type/decimal_test.rb +0 -56
  578. data/test/cases/type/unsigned_integer_test.rb +0 -18
  579. data/test/cases/xml_serialization_test.rb +0 -457
  580. data/test/connections/native_ibm_db/connection.rb +0 -44
  581. data/test/fixtures/naked/csv/accounts.csv +0 -1
  582. data/test/schema/i5/ibm_db_specific_schema.rb +0 -137
  583. data/test/schema/ids/ibm_db_specific_schema.rb +0 -140
  584. data/test/schema/luw/ibm_db_specific_schema.rb +0 -137
  585. data/test/schema/mysql_specific_schema.rb +0 -70
  586. data/test/schema/zOS/ibm_db_specific_schema.rb +0 -208
@@ -1,2182 +1,2501 @@
1
- require "cases/helper"
2
- require 'models/developer'
3
- require 'models/computer'
4
- require 'models/project'
5
- require 'models/company'
6
- require 'models/contract'
7
- require 'models/topic'
8
- require 'models/reply'
9
- require 'models/category'
10
- require 'models/image'
11
- require 'models/post'
12
- require 'models/author'
13
- require 'models/essay'
14
- require 'models/comment'
15
- require 'models/person'
16
- require 'models/reader'
17
- require 'models/tagging'
18
- require 'models/tag'
19
- require 'models/invoice'
20
- require 'models/line_item'
21
- require 'models/car'
22
- require 'models/bulb'
23
- require 'models/engine'
24
- require 'models/categorization'
25
- require 'models/minivan'
26
- require 'models/speedometer'
27
- require 'models/reference'
28
- require 'models/job'
29
- require 'models/college'
30
- require 'models/student'
31
- require 'models/pirate'
32
- require 'models/ship'
33
- require 'models/treasure'
34
- require 'models/parrot'
35
- require 'models/tyre'
36
- require 'models/subscriber'
37
- require 'models/subscription'
38
- require 'models/zine'
39
- require 'models/interest'
40
-
41
- class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCase
42
- fixtures :authors, :posts, :comments, :author_addresses
43
-
44
- def test_should_generate_valid_sql
45
- author = authors(:david)
46
- # this can fail on adapters which require ORDER BY expressions to be included in the SELECT expression
47
- # if the reorder clauses are not correctly handled
48
- assert author.posts_with_comments_sorted_by_comment_id.where('comments.id > 0').reorder('posts.comments_count DESC', 'posts.tags_count DESC').last
49
- end
50
- end
51
-
52
- class HasManyAssociationsTestPrimaryKeys < ActiveRecord::TestCase
53
- fixtures :authors, :essays, :subscribers, :subscriptions, :people
54
-
55
- def test_custom_primary_key_on_new_record_should_fetch_with_query
56
- subscriber = Subscriber.new(nick: 'webster132')
57
- assert !subscriber.subscriptions.loaded?
58
-
59
- assert_queries 1 do
60
- assert_equal 2, subscriber.subscriptions.size
61
- end
62
-
63
- assert_equal subscriber.subscriptions, Subscription.where(subscriber_id: 'webster132')
64
- end
65
-
66
- def test_association_primary_key_on_new_record_should_fetch_with_query
67
- author = Author.new(:name => "David")
68
- assert !author.essays.loaded?
69
-
70
- assert_queries 1 do
71
- assert_equal 1, author.essays.size
72
- end
73
-
74
- assert_equal author.essays, Essay.where(writer_id: "David")
75
- end
76
-
77
- def test_has_many_custom_primary_key
78
- david = authors(:david)
79
- assert_equal david.essays, Essay.where(writer_id: "David")
80
- end
81
-
82
- def test_has_many_assignment_with_custom_primary_key
83
- david = people(:david)
84
-
85
- assert_equal ["A Modest Proposal"], david.essays.map(&:name)
86
- david.essays = [Essay.create!(name: "Remote Work" )]
87
- assert_equal ["Remote Work"], david.essays.map(&:name)
88
- end
89
-
90
- def test_blank_custom_primary_key_on_new_record_should_not_run_queries
91
- author = Author.new
92
- assert !author.essays.loaded?
93
-
94
- assert_queries 0 do
95
- assert_equal 0, author.essays.size
96
- end
97
- end
98
- end
99
-
100
- class HasManyAssociationsTest < ActiveRecord::TestCase
101
- fixtures :accounts, :categories, :companies, :developers, :projects,
102
- :developers_projects, :topics, :authors, :comments,
103
- :posts, :readers, :taggings, :cars, :jobs, :tags,
104
- :categorizations, :zines, :interests
105
-
106
- def setup
107
- Client.destroyed_client_ids.clear
108
- end
109
-
110
- def test_sti_subselect_count
111
- tag = Tag.first
112
- len = Post.tagged_with(tag.id).limit(10).size
113
- assert_operator len, :>, 0
114
- end
115
-
116
- def test_anonymous_has_many
117
- developer = Class.new(ActiveRecord::Base) {
118
- self.table_name = 'developers'
119
- dev = self
120
-
121
- developer_project = Class.new(ActiveRecord::Base) {
122
- self.table_name = 'developers_projects'
123
- belongs_to :developer, :anonymous_class => dev
124
- }
125
- has_many :developer_projects, :anonymous_class => developer_project, :foreign_key => 'developer_id'
126
- }
127
- dev = developer.first
128
- named = Developer.find(dev.id)
129
- assert_operator dev.developer_projects.count, :>, 0
130
- assert_equal named.projects.map(&:id).sort,
131
- dev.developer_projects.map(&:project_id).sort
132
- end
133
-
134
- def test_default_scope_on_relations_is_not_cached
135
- counter = 0
136
- posts = Class.new(ActiveRecord::Base) {
137
- self.table_name = 'posts'
138
- self.inheritance_column = 'not_there'
139
- post = self
140
-
141
- comments = Class.new(ActiveRecord::Base) {
142
- self.table_name = 'comments'
143
- self.inheritance_column = 'not_there'
144
- belongs_to :post, :anonymous_class => post
145
- default_scope -> {
146
- counter += 1
147
- where("id = :inc", :inc => counter)
148
- }
149
- }
150
- has_many :comments, :anonymous_class => comments, :foreign_key => 'post_id'
151
- }
152
- assert_equal 0, counter
153
- post = posts.first
154
- assert_equal 0, counter
155
- sql = capture_sql { post.comments.to_a }
156
- post.comments.reset
157
- assert_not_equal sql, capture_sql { post.comments.to_a }
158
- end
159
-
160
- def test_has_many_build_with_options
161
- college = College.create(name: 'UFMT')
162
- Student.create(active: true, college_id: college.id, name: 'Sarah')
163
-
164
- assert_equal college.students, Student.where(active: true, college_id: college.id)
165
- end
166
-
167
- def test_create_from_association_should_respect_default_scope
168
- car = Car.create(:name => 'honda')
169
- assert_equal 'honda', car.name
170
-
171
- bulb = Bulb.create
172
- assert_equal 'defaulty', bulb.name
173
-
174
- bulb = car.bulbs.build
175
- assert_equal 'defaulty', bulb.name
176
-
177
- bulb = car.bulbs.create
178
- assert_equal 'defaulty', bulb.name
179
-
180
- bulb = car.bulbs.create(:name => 'exotic')
181
- assert_equal 'exotic', bulb.name
182
- end
183
-
184
- def test_build_from_association_should_respect_scope
185
- author = Author.new
186
-
187
- post = author.thinking_posts.build
188
- assert_equal 'So I was thinking', post.title
189
- end
190
-
191
- def test_create_from_association_with_nil_values_should_work
192
- car = Car.create(:name => 'honda')
193
-
194
- bulb = car.bulbs.new(nil)
195
- assert_equal 'defaulty', bulb.name
196
-
197
- bulb = car.bulbs.build(nil)
198
- assert_equal 'defaulty', bulb.name
199
-
200
- bulb = car.bulbs.create(nil)
201
- assert_equal 'defaulty', bulb.name
202
- end
203
-
204
- def test_do_not_call_callbacks_for_delete_all
205
- car = Car.create(:name => 'honda')
206
- car.funky_bulbs.create!
207
- assert_nothing_raised { car.reload.funky_bulbs.delete_all }
208
- assert_equal 0, Bulb.count, "bulbs should have been deleted using :delete_all strategy"
209
- end
210
-
211
- def test_delete_all_on_association_is_the_same_as_not_loaded
212
- author = authors :david
213
- author.thinking_posts.create!(:body => "test")
214
- author.reload
215
- expected_sql = capture_sql { author.thinking_posts.delete_all }
216
-
217
- author.thinking_posts.create!(:body => "test")
218
- author.reload
219
- author.thinking_posts.inspect
220
- loaded_sql = capture_sql { author.thinking_posts.delete_all }
221
- assert_equal(expected_sql, loaded_sql)
222
- end
223
-
224
- def test_delete_all_on_association_with_nil_dependency_is_the_same_as_not_loaded
225
- author = authors :david
226
- author.posts.create!(:title => "test", :body => "body")
227
- author.reload
228
- expected_sql = capture_sql { author.posts.delete_all }
229
-
230
- author.posts.create!(:title => "test", :body => "body")
231
- author.reload
232
- author.posts.to_a
233
- loaded_sql = capture_sql { author.posts.delete_all }
234
- assert_equal(expected_sql, loaded_sql)
235
- end
236
-
237
- def test_building_the_associated_object_with_implicit_sti_base_class
238
- firm = DependentFirm.new
239
- company = firm.companies.build
240
- assert_kind_of Company, company, "Expected #{company.class} to be a Company"
241
- end
242
-
243
- def test_building_the_associated_object_with_explicit_sti_base_class
244
- firm = DependentFirm.new
245
- company = firm.companies.build(:type => "Company")
246
- assert_kind_of Company, company, "Expected #{company.class} to be a Company"
247
- end
248
-
249
- def test_building_the_associated_object_with_sti_subclass
250
- firm = DependentFirm.new
251
- company = firm.companies.build(:type => "Client")
252
- assert_kind_of Client, company, "Expected #{company.class} to be a Client"
253
- end
254
-
255
- def test_building_the_associated_object_with_an_invalid_type
256
- firm = DependentFirm.new
257
- assert_raise(ActiveRecord::SubclassNotFound) { firm.companies.build(:type => "Invalid") }
258
- end
259
-
260
- def test_building_the_associated_object_with_an_unrelated_type
261
- firm = DependentFirm.new
262
- assert_raise(ActiveRecord::SubclassNotFound) { firm.companies.build(:type => "Account") }
263
- end
264
-
265
- test "building the association with an array" do
266
- speedometer = Speedometer.new(speedometer_id: "a")
267
- data = [{name: "first"}, {name: "second"}]
268
- speedometer.minivans.build(data)
269
-
270
- assert_equal 2, speedometer.minivans.size
271
- assert speedometer.save
272
- assert_equal ["first", "second"], speedometer.reload.minivans.map(&:name)
273
- end
274
-
275
- def test_association_keys_bypass_attribute_protection
276
- car = Car.create(:name => 'honda')
277
-
278
- bulb = car.bulbs.new
279
- assert_equal car.id, bulb.car_id
280
-
281
- bulb = car.bulbs.new :car_id => car.id + 1
282
- assert_equal car.id, bulb.car_id
283
-
284
- bulb = car.bulbs.build
285
- assert_equal car.id, bulb.car_id
286
-
287
- bulb = car.bulbs.build :car_id => car.id + 1
288
- assert_equal car.id, bulb.car_id
289
-
290
- bulb = car.bulbs.create
291
- assert_equal car.id, bulb.car_id
292
-
293
- bulb = car.bulbs.create :car_id => car.id + 1
294
- assert_equal car.id, bulb.car_id
295
- end
296
-
297
- def test_association_protect_foreign_key
298
- invoice = Invoice.create
299
-
300
- line_item = invoice.line_items.new
301
- assert_equal invoice.id, line_item.invoice_id
302
-
303
- line_item = invoice.line_items.new :invoice_id => invoice.id + 1
304
- assert_equal invoice.id, line_item.invoice_id
305
-
306
- line_item = invoice.line_items.build
307
- assert_equal invoice.id, line_item.invoice_id
308
-
309
- line_item = invoice.line_items.build :invoice_id => invoice.id + 1
310
- assert_equal invoice.id, line_item.invoice_id
311
-
312
- line_item = invoice.line_items.create
313
- assert_equal invoice.id, line_item.invoice_id
314
-
315
- line_item = invoice.line_items.create :invoice_id => invoice.id + 1
316
- assert_equal invoice.id, line_item.invoice_id
317
- end
318
-
319
- # When creating objects on the association, we must not do it within a scope (even though it
320
- # would be convenient), because this would cause that scope to be applied to any callbacks etc.
321
- def test_build_and_create_should_not_happen_within_scope
322
- car = cars(:honda)
323
- scoped_count = car.foo_bulbs.where_values.count
324
-
325
- bulb = car.foo_bulbs.build
326
- assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
327
-
328
- bulb = car.foo_bulbs.create
329
- assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
330
-
331
- bulb = car.foo_bulbs.create!
332
- assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
333
- end
334
-
335
- def test_no_sql_should_be_fired_if_association_already_loaded
336
- Car.create(:name => 'honda')
337
- bulbs = Car.first.bulbs
338
- bulbs.to_a # to load all instances of bulbs
339
-
340
- assert_no_queries do
341
- bulbs.first()
342
- bulbs.first({})
343
- end
344
-
345
- assert_no_queries do
346
- bulbs.second()
347
- bulbs.second({})
348
- end
349
-
350
- assert_no_queries do
351
- bulbs.third()
352
- bulbs.third({})
353
- end
354
-
355
- assert_no_queries do
356
- bulbs.fourth()
357
- bulbs.fourth({})
358
- end
359
-
360
- assert_no_queries do
361
- bulbs.fifth()
362
- bulbs.fifth({})
363
- end
364
-
365
- assert_no_queries do
366
- bulbs.forty_two()
367
- bulbs.forty_two({})
368
- end
369
-
370
- assert_no_queries do
371
- bulbs.last()
372
- bulbs.last({})
373
- end
374
- end
375
-
376
- def test_create_resets_cached_counters
377
- person = Person.create!(:first_name => 'tenderlove')
378
- post = Post.first
379
-
380
- assert_equal [], person.readers
381
- assert_nil person.readers.find_by_post_id(post.id)
382
-
383
- person.readers.create(:post_id => post.id)
384
-
385
- assert_equal 1, person.readers.count
386
- assert_equal 1, person.readers.length
387
- assert_equal post, person.readers.first.post
388
- assert_equal person, person.readers.first.person
389
- end
390
-
391
- def force_signal37_to_load_all_clients_of_firm
392
- companies(:first_firm).clients_of_firm.each {|f| }
393
- end
394
-
395
- # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
396
- def test_counting_with_counter_sql
397
- assert_equal 3, Firm.all.merge!(:order => "id").first.clients.count
398
- end
399
-
400
- def test_counting
401
- assert_equal 3, Firm.all.merge!(:order => "id").first.plain_clients.count
402
- end
403
-
404
- def test_counting_with_single_hash
405
- assert_equal 1, Firm.all.merge!(:order => "id").first.plain_clients.where(:name => "Microsoft").count
406
- end
407
-
408
- def test_counting_with_column_name_and_hash
409
- assert_equal 3, Firm.all.merge!(:order => "id").first.plain_clients.count(:name)
410
- end
411
-
412
- def test_counting_with_association_limit
413
- firm = companies(:first_firm)
414
- assert_equal firm.limited_clients.length, firm.limited_clients.size
415
- assert_equal firm.limited_clients.length, firm.limited_clients.count
416
- end
417
-
418
- def test_finding
419
- assert_equal 3, Firm.all.merge!(:order => "id").first.clients.length
420
- end
421
-
422
- def test_finding_array_compatibility
423
- assert_equal 3, Firm.order(:id).find{|f| f.id > 0}.clients.length
424
- end
425
-
426
- def test_find_many_with_merged_options
427
- assert_equal 1, companies(:first_firm).limited_clients.size
428
- assert_equal 1, companies(:first_firm).limited_clients.to_a.size
429
- assert_equal 3, companies(:first_firm).limited_clients.limit(nil).to_a.size
430
- end
431
-
432
- def test_find_should_append_to_association_order
433
- ordered_clients = companies(:first_firm).clients_sorted_desc.order('companies.id')
434
- assert_equal ['id DESC', 'companies.id'], ordered_clients.order_values
435
- end
436
-
437
- def test_dynamic_find_should_respect_association_order
438
- assert_equal companies(:another_first_firm_client), companies(:first_firm).clients_sorted_desc.where("type = 'Client'").first
439
- assert_equal companies(:another_first_firm_client), companies(:first_firm).clients_sorted_desc.find_by_type('Client')
440
- end
441
-
442
- def test_taking
443
- posts(:other_by_bob).destroy
444
- assert_equal posts(:misc_by_bob), authors(:bob).posts.take
445
- assert_equal posts(:misc_by_bob), authors(:bob).posts.take!
446
- authors(:bob).posts.to_a
447
- assert_equal posts(:misc_by_bob), authors(:bob).posts.take
448
- assert_equal posts(:misc_by_bob), authors(:bob).posts.take!
449
- end
450
-
451
- def test_taking_not_found
452
- authors(:bob).posts.delete_all
453
- assert_raise(ActiveRecord::RecordNotFound) { authors(:bob).posts.take! }
454
- authors(:bob).posts.to_a
455
- assert_raise(ActiveRecord::RecordNotFound) { authors(:bob).posts.take! }
456
- end
457
-
458
- def test_taking_with_a_number
459
- # taking from unloaded Relation
460
- bob = Author.find(authors(:bob).id)
461
- assert_equal [posts(:misc_by_bob)], bob.posts.take(1)
462
- bob = Author.find(authors(:bob).id)
463
- assert_equal [posts(:misc_by_bob), posts(:other_by_bob)], bob.posts.take(2)
464
-
465
- # taking from loaded Relation
466
- bob.posts.to_a
467
- assert_equal [posts(:misc_by_bob)], authors(:bob).posts.take(1)
468
- assert_equal [posts(:misc_by_bob), posts(:other_by_bob)], authors(:bob).posts.take(2)
469
- end
470
-
471
- def test_taking_with_inverse_of
472
- interests(:woodsmanship).destroy
473
- interests(:survival).destroy
474
-
475
- zine = zines(:going_out)
476
- interest = zine.interests.take
477
- assert_equal interests(:hunting), interest
478
- assert_same zine, interest.zine
479
- end
480
-
481
- def test_cant_save_has_many_readonly_association
482
- authors(:david).readonly_comments.each { |c| assert_raise(ActiveRecord::ReadOnlyRecord) { c.save! } }
483
- authors(:david).readonly_comments.each { |c| assert c.readonly? }
484
- end
485
-
486
- def test_finding_default_orders
487
- assert_equal "Summit", Firm.all.merge!(:order => "id").first.clients.first.name
488
- end
489
-
490
- def test_finding_with_different_class_name_and_order
491
- assert_equal "Apex", Firm.all.merge!(:order => "id").first.clients_sorted_desc.first.name
492
- end
493
-
494
- def test_finding_with_foreign_key
495
- assert_equal "Microsoft", Firm.all.merge!(:order => "id").first.clients_of_firm.first.name
496
- end
497
-
498
- def test_finding_with_condition
499
- assert_equal "Microsoft", Firm.all.merge!(:order => "id").first.clients_like_ms.first.name
500
- end
501
-
502
- def test_finding_with_condition_hash
503
- assert_equal "Microsoft", Firm.all.merge!(:order => "id").first.clients_like_ms_with_hash_conditions.first.name
504
- end
505
-
506
- def test_finding_using_primary_key
507
- assert_equal "Summit", Firm.all.merge!(:order => "id").first.clients_using_primary_key.first.name
508
- end
509
-
510
- def test_update_all_on_association_accessed_before_save
511
- firm = Firm.new(name: 'Firm')
512
- firm.clients << Client.first
513
- firm.save!
514
- assert_equal firm.clients.count, firm.clients.update_all(description: 'Great!')
515
- end
516
-
517
- def test_belongs_to_sanity
518
- c = Client.new
519
- assert_nil c.firm, "belongs_to failed sanity check on new object"
520
- end
521
-
522
- def test_find_ids
523
- firm = Firm.all.merge!(:order => "id").first
524
-
525
- assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find }
526
-
527
- client = firm.clients.find(2)
528
- assert_kind_of Client, client
529
-
530
- client_ary = firm.clients.find([2])
531
- assert_kind_of Array, client_ary
532
- assert_equal client, client_ary.first
533
-
534
- client_ary = firm.clients.find(2, 3)
535
- assert_kind_of Array, client_ary
536
- assert_equal 2, client_ary.size
537
- assert_equal client, client_ary.first
538
-
539
- assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(2, 99) }
540
- end
541
-
542
- def test_find_ids_and_inverse_of
543
- force_signal37_to_load_all_clients_of_firm
544
-
545
- firm = companies(:first_firm)
546
- client = firm.clients_of_firm.find(3)
547
- assert_kind_of Client, client
548
-
549
- client_ary = firm.clients_of_firm.find([3])
550
- assert_kind_of Array, client_ary
551
- assert_equal client, client_ary.first
552
- end
553
-
554
- def test_find_all
555
- firm = Firm.all.merge!(:order => "id").first
556
- assert_equal 3, firm.clients.where("#{QUOTED_TYPE} = 'Client'").to_a.length
557
- assert_equal 1, firm.clients.where("name = 'Summit'").to_a.length
558
- end
559
-
560
- def test_find_each
561
- firm = companies(:first_firm)
562
-
563
- assert ! firm.clients.loaded?
564
-
565
- assert_queries(4) do
566
- firm.clients.find_each(:batch_size => 1) {|c| assert_equal firm.id, c.firm_id }
567
- end
568
-
569
- assert ! firm.clients.loaded?
570
- end
571
-
572
- def test_find_each_with_conditions
573
- firm = companies(:first_firm)
574
-
575
- assert_queries(2) do
576
- firm.clients.where(name: 'Microsoft').find_each(batch_size: 1) do |c|
577
- assert_equal firm.id, c.firm_id
578
- assert_equal "Microsoft", c.name
579
- end
580
- end
581
-
582
- assert ! firm.clients.loaded?
583
- end
584
-
585
- def test_find_in_batches
586
- firm = companies(:first_firm)
587
-
588
- assert ! firm.clients.loaded?
589
-
590
- assert_queries(2) do
591
- firm.clients.find_in_batches(:batch_size => 2) do |clients|
592
- clients.each {|c| assert_equal firm.id, c.firm_id }
593
- end
594
- end
595
-
596
- assert ! firm.clients.loaded?
597
- end
598
-
599
- def test_find_all_sanitized
600
- # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
601
- firm = Firm.all.merge!(:order => "id").first
602
- summit = firm.clients.where("name = 'Summit'").to_a
603
- assert_equal summit, firm.clients.where("name = ?", "Summit").to_a
604
- assert_equal summit, firm.clients.where("name = :name", { :name => "Summit" }).to_a
605
- end
606
-
607
- def test_find_first
608
- firm = Firm.all.merge!(:order => "id").first
609
- client2 = Client.find(2)
610
- assert_equal firm.clients.first, firm.clients.order("id").first
611
- assert_equal client2, firm.clients.where("#{QUOTED_TYPE} = 'Client'").order("id").first
612
- end
613
-
614
- def test_find_first_sanitized
615
- firm = Firm.all.merge!(:order => "id").first
616
- client2 = Client.find(2)
617
- assert_equal client2, firm.clients.merge!(:where => ["#{QUOTED_TYPE} = ?", 'Client'], :order => "id").first
618
- assert_equal client2, firm.clients.merge!(:where => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }], :order => "id").first
619
- end
620
-
621
- def test_find_all_with_include_and_conditions
622
- assert_nothing_raised do
623
- Developer.all.merge!(:joins => :audit_logs, :where => {'audit_logs.message' => nil, :name => 'Smith'}).to_a
624
- end
625
- end
626
-
627
- def test_find_in_collection
628
- assert_equal Client.find(2).name, companies(:first_firm).clients.find(2).name
629
- assert_raise(ActiveRecord::RecordNotFound) { companies(:first_firm).clients.find(6) }
630
- end
631
-
632
- def test_find_grouped
633
- all_clients_of_firm1 = Client.all.merge!(:where => "firm_id = 1").to_a
634
- grouped_clients_of_firm1 = Client.all.merge!(:where => "firm_id = 1", :group => "firm_id", :select => 'firm_id, count(id) as clients_count').to_a
635
- assert_equal 3, all_clients_of_firm1.size
636
- assert_equal 1, grouped_clients_of_firm1.size
637
- end
638
-
639
- def test_find_scoped_grouped
640
- assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.size
641
- assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.length
642
- assert_equal 3, companies(:first_firm).clients_grouped_by_name.size
643
- assert_equal 3, companies(:first_firm).clients_grouped_by_name.length
644
- end
645
-
646
- def test_find_scoped_grouped_having
647
- assert_equal 1, authors(:david).popular_grouped_posts.length
648
- assert_equal 0, authors(:mary).popular_grouped_posts.length
649
- end
650
-
651
- def test_default_select
652
- assert_equal Comment.column_names.sort, posts(:welcome).comments.first.attributes.keys.sort
653
- end
654
-
655
- def test_select_query_method
656
- assert_equal ['id', 'body'], posts(:welcome).comments.select(:id, :body).first.attributes.keys
657
- end
658
-
659
- def test_select_with_block
660
- assert_equal [1], posts(:welcome).comments.select { |c| c.id == 1 }.map(&:id)
661
- end
662
-
663
- def test_select_without_foreign_key
664
- assert_equal companies(:first_firm).accounts.first.credit_limit, companies(:first_firm).accounts.select(:credit_limit).first.credit_limit
665
- end
666
-
667
- def test_adding
668
- force_signal37_to_load_all_clients_of_firm
669
- natural = Client.new("name" => "Natural Company")
670
- companies(:first_firm).clients_of_firm << natural
671
- assert_equal 3, companies(:first_firm).clients_of_firm.size # checking via the collection
672
- assert_equal 3, companies(:first_firm).clients_of_firm(true).size # checking using the db
673
- assert_equal natural, companies(:first_firm).clients_of_firm.last
674
- end
675
-
676
- def test_adding_using_create
677
- first_firm = companies(:first_firm)
678
- assert_equal 3, first_firm.plain_clients.size
679
- first_firm.plain_clients.create(:name => "Natural Company")
680
- assert_equal 4, first_firm.plain_clients.length
681
- assert_equal 4, first_firm.plain_clients.size
682
- end
683
-
684
- def test_create_with_bang_on_has_many_when_parent_is_new_raises
685
- error = assert_raise(ActiveRecord::RecordNotSaved) do
686
- firm = Firm.new
687
- firm.plain_clients.create! :name=>"Whoever"
688
- end
689
-
690
- assert_equal "You cannot call create unless the parent is saved", error.message
691
- end
692
-
693
- def test_regular_create_on_has_many_when_parent_is_new_raises
694
- error = assert_raise(ActiveRecord::RecordNotSaved) do
695
- firm = Firm.new
696
- firm.plain_clients.create :name=>"Whoever"
697
- end
698
-
699
- assert_equal "You cannot call create unless the parent is saved", error.message
700
- end
701
-
702
- def test_create_with_bang_on_has_many_raises_when_record_not_saved
703
- assert_raise(ActiveRecord::RecordInvalid) do
704
- firm = Firm.all.merge!(:order => "id").first
705
- firm.plain_clients.create!
706
- end
707
- end
708
-
709
- def test_create_with_bang_on_habtm_when_parent_is_new_raises
710
- error = assert_raise(ActiveRecord::RecordNotSaved) do
711
- Developer.new("name" => "Aredridel").projects.create!
712
- end
713
-
714
- assert_equal "You cannot call create unless the parent is saved", error.message
715
- end
716
-
717
- def test_adding_a_mismatch_class
718
- assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << nil }
719
- assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << 1 }
720
- assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << Topic.find(1) }
721
- end
722
-
723
- def test_adding_a_collection
724
- force_signal37_to_load_all_clients_of_firm
725
- companies(:first_firm).clients_of_firm.concat([Client.new("name" => "Natural Company"), Client.new("name" => "Apple")])
726
- assert_equal 4, companies(:first_firm).clients_of_firm.size
727
- assert_equal 4, companies(:first_firm).clients_of_firm(true).size
728
- end
729
-
730
- def test_transactions_when_adding_to_persisted
731
- good = Client.new(:name => "Good")
732
- bad = Client.new(:name => "Bad", :raise_on_save => true)
733
-
734
- begin
735
- companies(:first_firm).clients_of_firm.concat(good, bad)
736
- rescue Client::RaisedOnSave
737
- end
738
-
739
- assert !companies(:first_firm).clients_of_firm(true).include?(good)
740
- end
741
-
742
- def test_transactions_when_adding_to_new_record
743
- assert_no_queries(ignore_none: false) do
744
- firm = Firm.new
745
- firm.clients_of_firm.concat(Client.new("name" => "Natural Company"))
746
- end
747
- end
748
-
749
- def test_inverse_on_before_validate
750
- firm = companies(:first_firm)
751
- assert_queries(1) do
752
- firm.clients_of_firm << Client.new("name" => "Natural Company")
753
- end
754
- end
755
-
756
- def test_new_aliased_to_build
757
- company = companies(:first_firm)
758
- new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.new("name" => "Another Client") }
759
- assert !company.clients_of_firm.loaded?
760
-
761
- assert_equal "Another Client", new_client.name
762
- assert !new_client.persisted?
763
- assert_equal new_client, company.clients_of_firm.last
764
- end
765
-
766
- def test_build
767
- company = companies(:first_firm)
768
- new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build("name" => "Another Client") }
769
- assert !company.clients_of_firm.loaded?
770
-
771
- assert_equal "Another Client", new_client.name
772
- assert !new_client.persisted?
773
- assert_equal new_client, company.clients_of_firm.last
774
- end
775
-
776
- def test_collection_size_after_building
777
- company = companies(:first_firm) # company already has one client
778
- company.clients_of_firm.build("name" => "Another Client")
779
- company.clients_of_firm.build("name" => "Yet Another Client")
780
- assert_equal 4, company.clients_of_firm.size
781
- end
782
-
783
- def test_collection_not_empty_after_building
784
- company = companies(:first_firm)
785
- assert_predicate company.contracts, :empty?
786
- company.contracts.build
787
- assert_not_predicate company.contracts, :empty?
788
- end
789
-
790
- def test_collection_size_twice_for_regressions
791
- post = posts(:thinking)
792
- assert_equal 0, post.readers.size
793
- # This test needs a post that has no readers, we assert it to ensure it holds,
794
- # but need to reload the post because the very call to #size hides the bug.
795
- post.reload
796
- post.readers.build
797
- size1 = post.readers.size
798
- size2 = post.readers.size
799
- assert_equal size1, size2
800
- end
801
-
802
- def test_build_many
803
- company = companies(:first_firm)
804
- new_clients = assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) }
805
- assert_equal 2, new_clients.size
806
- end
807
-
808
- def test_build_followed_by_save_does_not_load_target
809
- companies(:first_firm).clients_of_firm.build("name" => "Another Client")
810
- assert companies(:first_firm).save
811
- assert !companies(:first_firm).clients_of_firm.loaded?
812
- end
813
-
814
- def test_build_without_loading_association
815
- first_topic = topics(:first)
816
- Reply.column_names
817
-
818
- assert_equal 1, first_topic.replies.length
819
-
820
- assert_no_queries do
821
- first_topic.replies.build(:title => "Not saved", :content => "Superstars")
822
- assert_equal 2, first_topic.replies.size
823
- end
824
-
825
- assert_equal 2, first_topic.replies.to_ary.size
826
- end
827
-
828
- def test_build_via_block
829
- company = companies(:first_firm)
830
- new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build {|client| client.name = "Another Client" } }
831
- assert !company.clients_of_firm.loaded?
832
-
833
- assert_equal "Another Client", new_client.name
834
- assert !new_client.persisted?
835
- assert_equal new_client, company.clients_of_firm.last
836
- end
837
-
838
- def test_build_many_via_block
839
- company = companies(:first_firm)
840
- new_clients = assert_no_queries(ignore_none: false) do
841
- company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client|
842
- client.name = "changed"
843
- end
844
- end
845
-
846
- assert_equal 2, new_clients.size
847
- assert_equal "changed", new_clients.first.name
848
- assert_equal "changed", new_clients.last.name
849
- end
850
-
851
- def test_create_without_loading_association
852
- first_firm = companies(:first_firm)
853
- Firm.column_names
854
- Client.column_names
855
-
856
- assert_equal 2, first_firm.clients_of_firm.size
857
- first_firm.clients_of_firm.reset
858
-
859
- assert_queries(1) do
860
- first_firm.clients_of_firm.create(:name => "Superstars")
861
- end
862
-
863
- assert_equal 3, first_firm.clients_of_firm.size
864
- end
865
-
866
- def test_create
867
- force_signal37_to_load_all_clients_of_firm
868
- new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client")
869
- assert new_client.persisted?
870
- assert_equal new_client, companies(:first_firm).clients_of_firm.last
871
- assert_equal new_client, companies(:first_firm).clients_of_firm(true).last
872
- end
873
-
874
- def test_create_many
875
- companies(:first_firm).clients_of_firm.create([{"name" => "Another Client"}, {"name" => "Another Client II"}])
876
- assert_equal 4, companies(:first_firm).clients_of_firm(true).size
877
- end
878
-
879
- def test_create_followed_by_save_does_not_load_target
880
- companies(:first_firm).clients_of_firm.create("name" => "Another Client")
881
- assert companies(:first_firm).save
882
- assert !companies(:first_firm).clients_of_firm.loaded?
883
- end
884
-
885
- def test_deleting
886
- force_signal37_to_load_all_clients_of_firm
887
- companies(:first_firm).clients_of_firm.delete(companies(:first_firm).clients_of_firm.first)
888
- assert_equal 1, companies(:first_firm).clients_of_firm.size
889
- assert_equal 1, companies(:first_firm).clients_of_firm(true).size
890
- end
891
-
892
- def test_deleting_before_save
893
- new_firm = Firm.new("name" => "A New Firm, Inc.")
894
- new_client = new_firm.clients_of_firm.build("name" => "Another Client")
895
- assert_equal 1, new_firm.clients_of_firm.size
896
- new_firm.clients_of_firm.delete(new_client)
897
- assert_equal 0, new_firm.clients_of_firm.size
898
- end
899
-
900
- def test_has_many_without_counter_cache_option
901
- # Ship has a conventionally named `treasures_count` column, but the counter_cache
902
- # option is not given on the association.
903
- ship = Ship.create(name: 'Countless', treasures_count: 10)
904
-
905
- assert_not ship.treasures.instance_variable_get('@association').send(:has_cached_counter?)
906
-
907
- # Count should come from sql count() of treasures rather than treasures_count attribute
908
- assert_equal ship.treasures.size, 0
909
-
910
- assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed" do
911
- ship.treasures.create(name: 'Gold')
912
- end
913
-
914
- assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed" do
915
- ship.treasures.destroy_all
916
- end
917
- end
918
-
919
- def test_deleting_updates_counter_cache
920
- topic = Topic.order("id ASC").first
921
- assert_equal topic.replies.to_a.size, topic.replies_count
922
-
923
- topic.replies.delete(topic.replies.first)
924
- topic.reload
925
- assert_equal topic.replies.to_a.size, topic.replies_count
926
- end
927
-
928
- def test_counter_cache_updates_in_memory_after_concat
929
- topic = Topic.create title: "Zoom-zoom-zoom"
930
-
931
- topic.replies << Reply.create(title: "re: zoom", content: "speedy quick!")
932
- assert_equal 1, topic.replies_count
933
- assert_equal 1, topic.replies.size
934
- assert_equal 1, topic.reload.replies.size
935
- end
936
-
937
- def test_counter_cache_updates_in_memory_after_create
938
- topic = Topic.create title: "Zoom-zoom-zoom"
939
-
940
- topic.replies.create!(title: "re: zoom", content: "speedy quick!")
941
- assert_equal 1, topic.replies_count
942
- assert_equal 1, topic.replies.size
943
- assert_equal 1, topic.reload.replies.size
944
- end
945
-
946
- def test_counter_cache_updates_in_memory_after_create_with_array
947
- topic = Topic.create title: "Zoom-zoom-zoom"
948
-
949
- topic.replies.create!([
950
- { title: "re: zoom", content: "speedy quick!" },
951
- { title: "re: zoom 2", content: "OMG lol!" },
952
- ])
953
- assert_equal 2, topic.replies_count
954
- assert_equal 2, topic.replies.size
955
- assert_equal 2, topic.reload.replies.size
956
- end
957
-
958
- def test_pushing_association_updates_counter_cache
959
- topic = Topic.order("id ASC").first
960
- reply = Reply.create!
961
-
962
- assert_difference "topic.reload.replies_count", 1 do
963
- topic.replies << reply
964
- end
965
- end
966
-
967
- def test_deleting_updates_counter_cache_without_dependent_option
968
- post = posts(:welcome)
969
-
970
- assert_difference "post.reload.tags_count", -1 do
971
- post.taggings.delete(post.taggings.first)
972
- end
973
- end
974
-
975
- def test_deleting_updates_counter_cache_with_dependent_delete_all
976
- post = posts(:welcome)
977
- post.update_columns(taggings_with_delete_all_count: post.tags_count)
978
-
979
- assert_difference "post.reload.taggings_with_delete_all_count", -1 do
980
- post.taggings_with_delete_all.delete(post.taggings_with_delete_all.first)
981
- end
982
- end
983
-
984
- def test_deleting_updates_counter_cache_with_dependent_destroy
985
- post = posts(:welcome)
986
- post.update_columns(taggings_with_destroy_count: post.tags_count)
987
-
988
- assert_difference "post.reload.taggings_with_destroy_count", -1 do
989
- post.taggings_with_destroy.delete(post.taggings_with_destroy.first)
990
- end
991
- end
992
-
993
- def test_calling_empty_with_counter_cache
994
- post = posts(:welcome)
995
- assert_queries(0) do
996
- assert_not post.comments.empty?
997
- end
998
- end
999
-
1000
- def test_custom_named_counter_cache
1001
- topic = topics(:first)
1002
-
1003
- assert_difference "topic.reload.replies_count", -1 do
1004
- topic.approved_replies.clear
1005
- end
1006
- end
1007
-
1008
- def test_calling_update_attributes_on_id_changes_the_counter_cache
1009
- topic = Topic.order("id ASC").first
1010
- original_count = topic.replies.to_a.size
1011
- assert_equal original_count, topic.replies_count
1012
-
1013
- first_reply = topic.replies.first
1014
- first_reply.update_attributes(:parent_id => nil)
1015
- assert_equal original_count - 1, topic.reload.replies_count
1016
-
1017
- first_reply.update_attributes(:parent_id => topic.id)
1018
- assert_equal original_count, topic.reload.replies_count
1019
- end
1020
-
1021
- def test_calling_update_attributes_changing_ids_doesnt_change_counter_cache
1022
- topic1 = Topic.find(1)
1023
- topic2 = Topic.find(3)
1024
- original_count1 = topic1.replies.to_a.size
1025
- original_count2 = topic2.replies.to_a.size
1026
-
1027
- reply1 = topic1.replies.first
1028
- reply2 = topic2.replies.first
1029
-
1030
- reply1.update_attributes(:parent_id => topic2.id)
1031
- assert_equal original_count1 - 1, topic1.reload.replies_count
1032
- assert_equal original_count2 + 1, topic2.reload.replies_count
1033
-
1034
- reply2.update_attributes(:parent_id => topic1.id)
1035
- assert_equal original_count1, topic1.reload.replies_count
1036
- assert_equal original_count2, topic2.reload.replies_count
1037
- end
1038
-
1039
- def test_deleting_a_collection
1040
- force_signal37_to_load_all_clients_of_firm
1041
- companies(:first_firm).clients_of_firm.create("name" => "Another Client")
1042
- assert_equal 3, companies(:first_firm).clients_of_firm.size
1043
- companies(:first_firm).clients_of_firm.delete([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1], companies(:first_firm).clients_of_firm[2]])
1044
- assert_equal 0, companies(:first_firm).clients_of_firm.size
1045
- assert_equal 0, companies(:first_firm).clients_of_firm(true).size
1046
- end
1047
-
1048
- def test_delete_all
1049
- force_signal37_to_load_all_clients_of_firm
1050
- companies(:first_firm).dependent_clients_of_firm.create("name" => "Another Client")
1051
- clients = companies(:first_firm).dependent_clients_of_firm.to_a
1052
- assert_equal 3, clients.count
1053
-
1054
- assert_difference "Client.count", -(clients.count) do
1055
- companies(:first_firm).dependent_clients_of_firm.delete_all
1056
- end
1057
- end
1058
-
1059
- def test_delete_all_with_not_yet_loaded_association_collection
1060
- force_signal37_to_load_all_clients_of_firm
1061
- companies(:first_firm).clients_of_firm.create("name" => "Another Client")
1062
- assert_equal 3, companies(:first_firm).clients_of_firm.size
1063
- companies(:first_firm).clients_of_firm.reset
1064
- companies(:first_firm).clients_of_firm.delete_all
1065
- assert_equal 0, companies(:first_firm).clients_of_firm.size
1066
- assert_equal 0, companies(:first_firm).clients_of_firm(true).size
1067
- end
1068
-
1069
- def test_transaction_when_deleting_persisted
1070
- good = Client.new(:name => "Good")
1071
- bad = Client.new(:name => "Bad", :raise_on_destroy => true)
1072
-
1073
- companies(:first_firm).clients_of_firm = [good, bad]
1074
-
1075
- begin
1076
- companies(:first_firm).clients_of_firm.destroy(good, bad)
1077
- rescue Client::RaisedOnDestroy
1078
- end
1079
-
1080
- assert_equal [good, bad], companies(:first_firm).clients_of_firm(true)
1081
- end
1082
-
1083
- def test_transaction_when_deleting_new_record
1084
- assert_no_queries(ignore_none: false) do
1085
- firm = Firm.new
1086
- client = Client.new("name" => "New Client")
1087
- firm.clients_of_firm << client
1088
- firm.clients_of_firm.destroy(client)
1089
- end
1090
- end
1091
-
1092
- def test_clearing_an_association_collection
1093
- firm = companies(:first_firm)
1094
- client_id = firm.clients_of_firm.first.id
1095
- assert_equal 2, firm.clients_of_firm.size
1096
-
1097
- firm.clients_of_firm.clear
1098
-
1099
- assert_equal 0, firm.clients_of_firm.size
1100
- assert_equal 0, firm.clients_of_firm(true).size
1101
- assert_equal [], Client.destroyed_client_ids[firm.id]
1102
-
1103
- # Should not be destroyed since the association is not dependent.
1104
- assert_nothing_raised do
1105
- assert_nil Client.find(client_id).firm
1106
- end
1107
- end
1108
-
1109
- def test_clearing_updates_counter_cache
1110
- topic = Topic.first
1111
-
1112
- assert_difference 'topic.reload.replies_count', -1 do
1113
- topic.replies.clear
1114
- end
1115
- end
1116
-
1117
- def test_clearing_updates_counter_cache_when_inverse_counter_cache_is_a_symbol_with_dependent_destroy
1118
- car = Car.first
1119
- car.engines.create!
1120
-
1121
- assert_difference 'car.reload.engines_count', -1 do
1122
- car.engines.clear
1123
- end
1124
- end
1125
-
1126
- def test_clearing_a_dependent_association_collection
1127
- firm = companies(:first_firm)
1128
- client_id = firm.dependent_clients_of_firm.first.id
1129
- assert_equal 2, firm.dependent_clients_of_firm.size
1130
- assert_equal 1, Client.find_by_id(client_id).client_of
1131
-
1132
- # :delete_all is called on each client since the dependent options is :destroy
1133
- firm.dependent_clients_of_firm.clear
1134
-
1135
- assert_equal 0, firm.dependent_clients_of_firm.size
1136
- assert_equal 0, firm.dependent_clients_of_firm(true).size
1137
- assert_equal [], Client.destroyed_client_ids[firm.id]
1138
-
1139
- # Should be destroyed since the association is dependent.
1140
- assert_nil Client.find_by_id(client_id)
1141
- end
1142
-
1143
- def test_delete_all_with_option_delete_all
1144
- firm = companies(:first_firm)
1145
- client_id = firm.dependent_clients_of_firm.first.id
1146
- firm.dependent_clients_of_firm.delete_all(:delete_all)
1147
- assert_nil Client.find_by_id(client_id)
1148
- end
1149
-
1150
- def test_delete_all_accepts_limited_parameters
1151
- firm = companies(:first_firm)
1152
- assert_raise(ArgumentError) do
1153
- firm.dependent_clients_of_firm.delete_all(:destroy)
1154
- end
1155
- end
1156
-
1157
- def test_clearing_an_exclusively_dependent_association_collection
1158
- firm = companies(:first_firm)
1159
- client_id = firm.exclusively_dependent_clients_of_firm.first.id
1160
- assert_equal 2, firm.exclusively_dependent_clients_of_firm.size
1161
-
1162
- assert_equal [], Client.destroyed_client_ids[firm.id]
1163
-
1164
- # :exclusively_dependent means each client is deleted directly from
1165
- # the database without looping through them calling destroy.
1166
- firm.exclusively_dependent_clients_of_firm.clear
1167
-
1168
- assert_equal 0, firm.exclusively_dependent_clients_of_firm.size
1169
- assert_equal 0, firm.exclusively_dependent_clients_of_firm(true).size
1170
- # no destroy-filters should have been called
1171
- assert_equal [], Client.destroyed_client_ids[firm.id]
1172
-
1173
- # Should be destroyed since the association is exclusively dependent.
1174
- assert_nil Client.find_by_id(client_id)
1175
- end
1176
-
1177
- def test_dependent_association_respects_optional_conditions_on_delete
1178
- firm = companies(:odegy)
1179
- Client.create(:client_of => firm.id, :name => "BigShot Inc.")
1180
- Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
1181
- # only one of two clients is included in the association due to the :conditions key
1182
- assert_equal 2, Client.where(client_of: firm.id).size
1183
- assert_equal 1, firm.dependent_conditional_clients_of_firm.size
1184
- firm.destroy
1185
- # only the correctly associated client should have been deleted
1186
- assert_equal 1, Client.where(client_of: firm.id).size
1187
- end
1188
-
1189
- def test_dependent_association_respects_optional_sanitized_conditions_on_delete
1190
- firm = companies(:odegy)
1191
- Client.create(:client_of => firm.id, :name => "BigShot Inc.")
1192
- Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
1193
- # only one of two clients is included in the association due to the :conditions key
1194
- assert_equal 2, Client.where(client_of: firm.id).size
1195
- assert_equal 1, firm.dependent_sanitized_conditional_clients_of_firm.size
1196
- firm.destroy
1197
- # only the correctly associated client should have been deleted
1198
- assert_equal 1, Client.where(client_of: firm.id).size
1199
- end
1200
-
1201
- def test_dependent_association_respects_optional_hash_conditions_on_delete
1202
- firm = companies(:odegy)
1203
- Client.create(:client_of => firm.id, :name => "BigShot Inc.")
1204
- Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
1205
- # only one of two clients is included in the association due to the :conditions key
1206
- assert_equal 2, Client.where(client_of: firm.id).size
1207
- assert_equal 1, firm.dependent_sanitized_conditional_clients_of_firm.size
1208
- firm.destroy
1209
- # only the correctly associated client should have been deleted
1210
- assert_equal 1, Client.where(client_of: firm.id).size
1211
- end
1212
-
1213
- def test_delete_all_association_with_primary_key_deletes_correct_records
1214
- firm = Firm.first
1215
- # break the vanilla firm_id foreign key
1216
- assert_equal 3, firm.clients.count
1217
- firm.clients.first.update_columns(firm_id: nil)
1218
- assert_equal 2, firm.clients(true).count
1219
- assert_equal 2, firm.clients_using_primary_key_with_delete_all.count
1220
- old_record = firm.clients_using_primary_key_with_delete_all.first
1221
- firm = Firm.first
1222
- firm.destroy
1223
- assert_nil Client.find_by_id(old_record.id)
1224
- end
1225
-
1226
- def test_creation_respects_hash_condition
1227
- ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.build
1228
-
1229
- assert ms_client.save
1230
- assert_equal 'Microsoft', ms_client.name
1231
-
1232
- another_ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.create
1233
-
1234
- assert another_ms_client.persisted?
1235
- assert_equal 'Microsoft', another_ms_client.name
1236
- end
1237
-
1238
- def test_clearing_without_initial_access
1239
- firm = companies(:first_firm)
1240
-
1241
- firm.clients_of_firm.clear
1242
-
1243
- assert_equal 0, firm.clients_of_firm.size
1244
- assert_equal 0, firm.clients_of_firm(true).size
1245
- end
1246
-
1247
- def test_deleting_a_item_which_is_not_in_the_collection
1248
- force_signal37_to_load_all_clients_of_firm
1249
- summit = Client.find_by_name('Summit')
1250
- companies(:first_firm).clients_of_firm.delete(summit)
1251
- assert_equal 2, companies(:first_firm).clients_of_firm.size
1252
- assert_equal 2, companies(:first_firm).clients_of_firm(true).size
1253
- assert_equal 2, summit.client_of
1254
- end
1255
-
1256
- def test_deleting_by_fixnum_id
1257
- david = Developer.find(1)
1258
-
1259
- assert_difference 'david.projects.count', -1 do
1260
- assert_equal 1, david.projects.delete(1).size
1261
- end
1262
-
1263
- assert_equal 1, david.projects.size
1264
- end
1265
-
1266
- def test_deleting_by_string_id
1267
- david = Developer.find(1)
1268
-
1269
- assert_difference 'david.projects.count', -1 do
1270
- assert_equal 1, david.projects.delete('1').size
1271
- end
1272
-
1273
- assert_equal 1, david.projects.size
1274
- end
1275
-
1276
- def test_deleting_self_type_mismatch
1277
- david = Developer.find(1)
1278
- david.projects.reload
1279
- assert_raise(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(Project.find(1).developers) }
1280
- end
1281
-
1282
- def test_destroying
1283
- force_signal37_to_load_all_clients_of_firm
1284
-
1285
- assert_difference "Client.count", -1 do
1286
- companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first)
1287
- end
1288
-
1289
- assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1290
- assert_equal 1, companies(:first_firm).clients_of_firm(true).size
1291
- end
1292
-
1293
- def test_destroying_by_fixnum_id
1294
- force_signal37_to_load_all_clients_of_firm
1295
-
1296
- assert_difference "Client.count", -1 do
1297
- companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first.id)
1298
- end
1299
-
1300
- assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1301
- assert_equal 1, companies(:first_firm).clients_of_firm(true).size
1302
- end
1303
-
1304
- def test_destroying_by_string_id
1305
- force_signal37_to_load_all_clients_of_firm
1306
-
1307
- assert_difference "Client.count", -1 do
1308
- companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first.id.to_s)
1309
- end
1310
-
1311
- assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1312
- assert_equal 1, companies(:first_firm).clients_of_firm(true).size
1313
- end
1314
-
1315
- def test_destroying_a_collection
1316
- force_signal37_to_load_all_clients_of_firm
1317
- companies(:first_firm).clients_of_firm.create("name" => "Another Client")
1318
- assert_equal 3, companies(:first_firm).clients_of_firm.size
1319
-
1320
- assert_difference "Client.count", -2 do
1321
- companies(:first_firm).clients_of_firm.destroy([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1]])
1322
- end
1323
-
1324
- assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1325
- assert_equal 1, companies(:first_firm).clients_of_firm(true).size
1326
- end
1327
-
1328
- def test_destroy_all
1329
- force_signal37_to_load_all_clients_of_firm
1330
- clients = companies(:first_firm).clients_of_firm.to_a
1331
- assert !clients.empty?, "37signals has clients after load"
1332
- destroyed = companies(:first_firm).clients_of_firm.destroy_all
1333
- assert_equal clients.sort_by(&:id), destroyed.sort_by(&:id)
1334
- assert destroyed.all? { |client| client.frozen? }, "destroyed clients should be frozen"
1335
- assert companies(:first_firm).clients_of_firm.empty?, "37signals has no clients after destroy all"
1336
- assert companies(:first_firm).clients_of_firm(true).empty?, "37signals has no clients after destroy all and refresh"
1337
- end
1338
-
1339
- def test_dependence
1340
- firm = companies(:first_firm)
1341
- assert_equal 3, firm.clients.size
1342
- firm.destroy
1343
- assert Client.all.merge!(:where => "firm_id=#{firm.id}").to_a.empty?
1344
- end
1345
-
1346
- def test_dependence_for_associations_with_hash_condition
1347
- david = authors(:david)
1348
- assert_difference('Post.count', -1) { assert david.destroy }
1349
- end
1350
-
1351
- def test_destroy_dependent_when_deleted_from_association
1352
- # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
1353
- firm = Firm.all.merge!(:order => "id").first
1354
- assert_equal 3, firm.clients.size
1355
-
1356
- client = firm.clients.first
1357
- firm.clients.delete(client)
1358
-
1359
- assert_raise(ActiveRecord::RecordNotFound) { Client.find(client.id) }
1360
- assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(client.id) }
1361
- assert_equal 2, firm.clients.size
1362
- end
1363
-
1364
- def test_three_levels_of_dependence
1365
- topic = Topic.create "title" => "neat and simple"
1366
- reply = topic.replies.create "title" => "neat and simple", "content" => "still digging it"
1367
- reply.replies.create "title" => "neat and simple", "content" => "ain't complaining"
1368
-
1369
- assert_nothing_raised { topic.destroy }
1370
- end
1371
-
1372
- uses_transaction :test_dependence_with_transaction_support_on_failure
1373
- def test_dependence_with_transaction_support_on_failure
1374
- firm = companies(:first_firm)
1375
- clients = firm.clients
1376
- assert_equal 3, clients.length
1377
- clients.last.instance_eval { def overwrite_to_raise() raise "Trigger rollback" end }
1378
-
1379
- firm.destroy rescue "do nothing"
1380
-
1381
- assert_equal 3, Client.all.merge!(:where => "firm_id=#{firm.id}").to_a.size
1382
- end
1383
-
1384
- def test_dependence_on_account
1385
- num_accounts = Account.count
1386
- companies(:first_firm).destroy
1387
- assert_equal num_accounts - 1, Account.count
1388
- end
1389
-
1390
- def test_depends_and_nullify
1391
- num_accounts = Account.count
1392
-
1393
- core = companies(:rails_core)
1394
- assert_equal accounts(:rails_core_account), core.account
1395
- assert_equal companies(:leetsoft, :jadedpixel), core.companies
1396
- core.destroy
1397
- assert_nil accounts(:rails_core_account).reload.firm_id
1398
- assert_nil companies(:leetsoft).reload.client_of
1399
- assert_nil companies(:jadedpixel).reload.client_of
1400
-
1401
- assert_equal num_accounts, Account.count
1402
- end
1403
-
1404
- def test_restrict_with_exception
1405
- firm = RestrictedWithExceptionFirm.create!(:name => 'restrict')
1406
- firm.companies.create(:name => 'child')
1407
-
1408
- assert !firm.companies.empty?
1409
- assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy }
1410
- assert RestrictedWithExceptionFirm.exists?(:name => 'restrict')
1411
- assert firm.companies.exists?(:name => 'child')
1412
- end
1413
-
1414
- def test_restrict_with_error
1415
- firm = RestrictedWithErrorFirm.create!(:name => 'restrict')
1416
- firm.companies.create(:name => 'child')
1417
-
1418
- assert !firm.companies.empty?
1419
-
1420
- firm.destroy
1421
-
1422
- assert !firm.errors.empty?
1423
-
1424
- assert_equal "Cannot delete record because dependent companies exist", firm.errors[:base].first
1425
- assert RestrictedWithErrorFirm.exists?(:name => 'restrict')
1426
- assert firm.companies.exists?(:name => 'child')
1427
- end
1428
-
1429
- def test_included_in_collection
1430
- assert_equal true, companies(:first_firm).clients.include?(Client.find(2))
1431
- end
1432
-
1433
- def test_included_in_collection_for_new_records
1434
- client = Client.create(:name => 'Persisted')
1435
- assert_nil client.client_of
1436
- assert_equal false, Firm.new.clients_of_firm.include?(client),
1437
- 'includes a client that does not belong to any firm'
1438
- end
1439
-
1440
- def test_adding_array_and_collection
1441
- assert_nothing_raised { Firm.first.clients + Firm.all.last.clients }
1442
- end
1443
-
1444
- def test_replace_with_less
1445
- firm = Firm.all.merge!(:order => "id").first
1446
- firm.clients = [companies(:first_client)]
1447
- assert firm.save, "Could not save firm"
1448
- firm.reload
1449
- assert_equal 1, firm.clients.length
1450
- end
1451
-
1452
- def test_replace_with_less_and_dependent_nullify
1453
- num_companies = Company.count
1454
- companies(:rails_core).companies = []
1455
- assert_equal num_companies, Company.count
1456
- end
1457
-
1458
- def test_replace_with_new
1459
- firm = Firm.all.merge!(:order => "id").first
1460
- firm.clients = [companies(:second_client), Client.new("name" => "New Client")]
1461
- firm.save
1462
- firm.reload
1463
- assert_equal 2, firm.clients.length
1464
- assert_equal false, firm.clients.include?(:first_client)
1465
- end
1466
-
1467
- def test_replace_failure
1468
- firm = companies(:first_firm)
1469
- account = Account.new
1470
- orig_accounts = firm.accounts.to_a
1471
-
1472
- assert !account.valid?
1473
- assert !orig_accounts.empty?
1474
- error = assert_raise ActiveRecord::RecordNotSaved do
1475
- firm.accounts = [account]
1476
- end
1477
-
1478
- assert_equal orig_accounts, firm.accounts
1479
- assert_equal "Failed to replace accounts because one or more of the " \
1480
- "new records could not be saved.", error.message
1481
- end
1482
-
1483
- def test_replace_with_same_content
1484
- firm = Firm.first
1485
- firm.clients = []
1486
- firm.save
1487
-
1488
- assert_queries(0, ignore_none: true) do
1489
- firm.clients = []
1490
- end
1491
- end
1492
-
1493
- def test_transactions_when_replacing_on_persisted
1494
- good = Client.new(:name => "Good")
1495
- bad = Client.new(:name => "Bad", :raise_on_save => true)
1496
-
1497
- companies(:first_firm).clients_of_firm = [good]
1498
-
1499
- begin
1500
- companies(:first_firm).clients_of_firm = [bad]
1501
- rescue Client::RaisedOnSave
1502
- end
1503
-
1504
- assert_equal [good], companies(:first_firm).clients_of_firm(true)
1505
- end
1506
-
1507
- def test_transactions_when_replacing_on_new_record
1508
- assert_no_queries(ignore_none: false) do
1509
- firm = Firm.new
1510
- firm.clients_of_firm = [Client.new("name" => "New Client")]
1511
- end
1512
- end
1513
-
1514
- def test_get_ids
1515
- assert_equal [companies(:first_client).id, companies(:second_client).id, companies(:another_first_firm_client).id], companies(:first_firm).client_ids
1516
- end
1517
-
1518
- def test_get_ids_for_loaded_associations
1519
- company = companies(:first_firm)
1520
- company.clients(true)
1521
- assert_queries(0) do
1522
- company.client_ids
1523
- company.client_ids
1524
- end
1525
- end
1526
-
1527
- def test_get_ids_for_unloaded_associations_does_not_load_them
1528
- company = companies(:first_firm)
1529
- assert !company.clients.loaded?
1530
- assert_equal [companies(:first_client).id, companies(:second_client).id, companies(:another_first_firm_client).id], company.client_ids
1531
- assert !company.clients.loaded?
1532
- end
1533
-
1534
- def test_get_ids_ignores_include_option
1535
- assert_equal [readers(:michael_welcome).id], posts(:welcome).readers_with_person_ids
1536
- end
1537
-
1538
- def test_get_ids_for_ordered_association
1539
- assert_equal [companies(:another_first_firm_client).id, companies(:second_client).id, companies(:first_client).id], companies(:first_firm).clients_ordered_by_name_ids
1540
- end
1541
-
1542
- def test_get_ids_for_association_on_new_record_does_not_try_to_find_records
1543
- Company.columns # Load schema information so we don't query below
1544
- Contract.columns # if running just this test.
1545
-
1546
- company = Company.new
1547
- assert_queries(0) do
1548
- company.contract_ids
1549
- end
1550
-
1551
- assert_equal [], company.contract_ids
1552
- end
1553
-
1554
- def test_set_ids_for_association_on_new_record_applies_association_correctly
1555
- contract_a = Contract.create!
1556
- contract_b = Contract.create!
1557
- Contract.create! # another contract
1558
- company = Company.new(:name => "Some Company")
1559
-
1560
- company.contract_ids = [contract_a.id, contract_b.id]
1561
- assert_equal [contract_a.id, contract_b.id], company.contract_ids
1562
- assert_equal [contract_a, contract_b], company.contracts
1563
-
1564
- company.save!
1565
- assert_equal company, contract_a.reload.company
1566
- assert_equal company, contract_b.reload.company
1567
- end
1568
-
1569
- def test_assign_ids_ignoring_blanks
1570
- firm = Firm.create!(:name => 'Apple')
1571
- firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, '']
1572
- firm.save!
1573
-
1574
- assert_equal 2, firm.clients(true).size
1575
- assert_equal true, firm.clients.include?(companies(:second_client))
1576
- end
1577
-
1578
- def test_get_ids_for_through
1579
- assert_equal [comments(:eager_other_comment1).id], authors(:mary).comment_ids
1580
- end
1581
-
1582
- def test_modifying_a_through_a_has_many_should_raise
1583
- [
1584
- lambda { authors(:mary).comment_ids = [comments(:greetings).id, comments(:more_greetings).id] },
1585
- lambda { authors(:mary).comments = [comments(:greetings), comments(:more_greetings)] },
1586
- lambda { authors(:mary).comments << Comment.create!(:body => "Yay", :post_id => 424242) },
1587
- lambda { authors(:mary).comments.delete(authors(:mary).comments.first) },
1588
- ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
1589
- end
1590
-
1591
- def test_dynamic_find_should_respect_association_order_for_through
1592
- assert_equal Comment.find(10), authors(:david).comments_desc.where("comments.type = 'SpecialComment'").first
1593
- assert_equal Comment.find(10), authors(:david).comments_desc.find_by_type('SpecialComment')
1594
- end
1595
-
1596
- def test_has_many_through_respects_hash_conditions
1597
- assert_equal authors(:david).hello_posts, authors(:david).hello_posts_with_hash_conditions
1598
- assert_equal authors(:david).hello_post_comments, authors(:david).hello_post_comments_with_hash_conditions
1599
- end
1600
-
1601
- def test_include_uses_array_include_after_loaded
1602
- firm = companies(:first_firm)
1603
- firm.clients.load_target
1604
-
1605
- client = firm.clients.first
1606
-
1607
- assert_no_queries do
1608
- assert firm.clients.loaded?
1609
- assert_equal true, firm.clients.include?(client)
1610
- end
1611
- end
1612
-
1613
- def test_include_checks_if_record_exists_if_target_not_loaded
1614
- firm = companies(:first_firm)
1615
- client = firm.clients.first
1616
-
1617
- firm.reload
1618
- assert ! firm.clients.loaded?
1619
- assert_queries(1) do
1620
- assert_equal true, firm.clients.include?(client)
1621
- end
1622
- assert ! firm.clients.loaded?
1623
- end
1624
-
1625
- def test_include_returns_false_for_non_matching_record_to_verify_scoping
1626
- firm = companies(:first_firm)
1627
- client = Client.create!(:name => 'Not Associated')
1628
-
1629
- assert ! firm.clients.loaded?
1630
- assert_equal false, firm.clients.include?(client)
1631
- end
1632
-
1633
- def test_calling_first_nth_or_last_on_association_should_not_load_association
1634
- firm = companies(:first_firm)
1635
- firm.clients.first
1636
- firm.clients.second
1637
- firm.clients.last
1638
- assert !firm.clients.loaded?
1639
- end
1640
-
1641
- def test_calling_first_or_last_on_loaded_association_should_not_fetch_with_query
1642
- firm = companies(:first_firm)
1643
- firm.clients.load_target
1644
- assert firm.clients.loaded?
1645
-
1646
- assert_no_queries(ignore_none: false) do
1647
- firm.clients.first
1648
- assert_equal 2, firm.clients.first(2).size
1649
- firm.clients.last
1650
- assert_equal 2, firm.clients.last(2).size
1651
- end
1652
- end
1653
-
1654
- def test_calling_first_or_last_on_existing_record_with_build_should_load_association
1655
- firm = companies(:first_firm)
1656
- firm.clients.build(:name => 'Foo')
1657
- assert !firm.clients.loaded?
1658
-
1659
- assert_queries 1 do
1660
- firm.clients.first
1661
- firm.clients.second
1662
- firm.clients.last
1663
- end
1664
-
1665
- assert firm.clients.loaded?
1666
- end
1667
-
1668
- def test_calling_first_nth_or_last_on_existing_record_with_create_should_not_load_association
1669
- firm = companies(:first_firm)
1670
- firm.clients.create(:name => 'Foo')
1671
- assert !firm.clients.loaded?
1672
-
1673
- assert_queries 3 do
1674
- firm.clients.first
1675
- firm.clients.second
1676
- firm.clients.last
1677
- end
1678
-
1679
- assert !firm.clients.loaded?
1680
- end
1681
-
1682
- def test_calling_first_nth_or_last_on_new_record_should_not_run_queries
1683
- firm = Firm.new
1684
-
1685
- assert_no_queries do
1686
- firm.clients.first
1687
- firm.clients.second
1688
- firm.clients.last
1689
- end
1690
- end
1691
-
1692
- def test_calling_first_or_last_with_integer_on_association_should_not_load_association
1693
- firm = companies(:first_firm)
1694
- firm.clients.create(:name => 'Foo')
1695
- assert !firm.clients.loaded?
1696
-
1697
- assert_queries 2 do
1698
- firm.clients.first(2)
1699
- firm.clients.last(2)
1700
- end
1701
-
1702
- assert !firm.clients.loaded?
1703
- end
1704
-
1705
- def test_calling_many_should_count_instead_of_loading_association
1706
- firm = companies(:first_firm)
1707
- assert_queries(1) do
1708
- firm.clients.many? # use count query
1709
- end
1710
- assert !firm.clients.loaded?
1711
- end
1712
-
1713
- def test_calling_many_on_loaded_association_should_not_use_query
1714
- firm = companies(:first_firm)
1715
- firm.clients.collect # force load
1716
- assert_no_queries { assert firm.clients.many? }
1717
- end
1718
-
1719
- def test_calling_many_should_defer_to_collection_if_using_a_block
1720
- firm = companies(:first_firm)
1721
- assert_queries(1) do
1722
- firm.clients.expects(:size).never
1723
- firm.clients.many? { true }
1724
- end
1725
- assert firm.clients.loaded?
1726
- end
1727
-
1728
- def test_calling_many_should_return_false_if_none_or_one
1729
- firm = companies(:another_firm)
1730
- assert !firm.clients_like_ms.many?
1731
- assert_equal 0, firm.clients_like_ms.size
1732
-
1733
- firm = companies(:first_firm)
1734
- assert !firm.limited_clients.many?
1735
- assert_equal 1, firm.limited_clients.size
1736
- end
1737
-
1738
- def test_calling_many_should_return_true_if_more_than_one
1739
- firm = companies(:first_firm)
1740
- assert firm.clients.many?
1741
- assert_equal 3, firm.clients.size
1742
- end
1743
-
1744
- def test_joins_with_namespaced_model_should_use_correct_type
1745
- old = ActiveRecord::Base.store_full_sti_class
1746
- ActiveRecord::Base.store_full_sti_class = true
1747
-
1748
- firm = Namespaced::Firm.create({ :name => 'Some Company' })
1749
- firm.clients.create({ :name => 'Some Client' })
1750
-
1751
- stats = Namespaced::Firm.all.merge!(
1752
- :select => "#{Namespaced::Firm.table_name}.id, COUNT(#{Namespaced::Client.table_name}.id) AS num_clients",
1753
- :joins => :clients,
1754
- :group => "#{Namespaced::Firm.table_name}.id"
1755
- ).find firm.id
1756
- assert_equal 1, stats.num_clients.to_i
1757
- ensure
1758
- ActiveRecord::Base.store_full_sti_class = old
1759
- end
1760
-
1761
- def test_association_proxy_transaction_method_starts_transaction_in_association_class
1762
- Comment.expects(:transaction)
1763
- Post.first.comments.transaction do
1764
- # nothing
1765
- end
1766
- end
1767
-
1768
- def test_sending_new_to_association_proxy_should_have_same_effect_as_calling_new
1769
- client_association = companies(:first_firm).clients
1770
- assert_equal client_association.new.attributes, client_association.send(:new).attributes
1771
- end
1772
-
1773
- def test_respond_to_private_class_methods
1774
- client_association = companies(:first_firm).clients
1775
- assert !client_association.respond_to?(:private_method)
1776
- assert client_association.respond_to?(:private_method, true)
1777
- end
1778
-
1779
- def test_creating_using_primary_key
1780
- firm = Firm.all.merge!(:order => "id").first
1781
- client = firm.clients_using_primary_key.create!(:name => 'test')
1782
- assert_equal firm.name, client.firm_name
1783
- end
1784
-
1785
- def test_defining_has_many_association_with_delete_all_dependency_lazily_evaluates_target_class
1786
- ActiveRecord::Reflection::AssociationReflection.any_instance.expects(:class_name).never
1787
- class_eval(<<-EOF, __FILE__, __LINE__ + 1)
1788
- class DeleteAllModel < ActiveRecord::Base
1789
- has_many :nonentities, :dependent => :delete_all
1790
- end
1791
- EOF
1792
- end
1793
-
1794
- def test_defining_has_many_association_with_nullify_dependency_lazily_evaluates_target_class
1795
- ActiveRecord::Reflection::AssociationReflection.any_instance.expects(:class_name).never
1796
- class_eval(<<-EOF, __FILE__, __LINE__ + 1)
1797
- class NullifyModel < ActiveRecord::Base
1798
- has_many :nonentities, :dependent => :nullify
1799
- end
1800
- EOF
1801
- end
1802
-
1803
- def test_attributes_are_being_set_when_initialized_from_has_many_association_with_where_clause
1804
- new_comment = posts(:welcome).comments.where(:body => "Some content").build
1805
- assert_equal new_comment.body, "Some content"
1806
- end
1807
-
1808
- def test_attributes_are_being_set_when_initialized_from_has_many_association_with_multiple_where_clauses
1809
- new_comment = posts(:welcome).comments.where(:body => "Some content").where(:type => 'SpecialComment').build
1810
- assert_equal new_comment.body, "Some content"
1811
- assert_equal new_comment.type, "SpecialComment"
1812
- assert_equal new_comment.post_id, posts(:welcome).id
1813
- end
1814
-
1815
- def test_include_method_in_has_many_association_should_return_true_for_instance_added_with_build
1816
- post = Post.new
1817
- comment = post.comments.build
1818
- assert_equal true, post.comments.include?(comment)
1819
- end
1820
-
1821
- def test_load_target_respects_protected_attributes
1822
- topic = Topic.create!
1823
- reply = topic.replies.create(:title => "reply 1")
1824
- reply.approved = false
1825
- reply.save!
1826
-
1827
- # Save with a different object instance, so the instance that's still held
1828
- # in topic.relies doesn't know about the changed attribute.
1829
- reply2 = Reply.find(reply.id)
1830
- reply2.approved = true
1831
- reply2.save!
1832
-
1833
- # Force loading the collection from the db. This will merge the existing
1834
- # object (reply) with what gets loaded from the db (which includes the
1835
- # changed approved attribute). approved is a protected attribute, so if mass
1836
- # assignment is used, it won't get updated and will still be false.
1837
- first = topic.replies.to_a.first
1838
- assert_equal reply.id, first.id
1839
- assert_equal true, first.approved?
1840
- end
1841
-
1842
- def test_to_a_should_dup_target
1843
- ary = topics(:first).replies.to_a
1844
- target = topics(:first).replies.target
1845
-
1846
- assert_not_equal target.object_id, ary.object_id
1847
- end
1848
-
1849
- def test_merging_with_custom_attribute_writer
1850
- bulb = Bulb.new(:color => "red")
1851
- assert_equal "RED!", bulb.color
1852
-
1853
- car = Car.create!
1854
- car.bulbs << bulb
1855
-
1856
- assert_equal "RED!", car.bulbs.to_a.first.color
1857
- end
1858
-
1859
- def test_abstract_class_with_polymorphic_has_many
1860
- post = SubStiPost.create! :title => "fooo", :body => "baa"
1861
- tagging = Tagging.create! :taggable => post
1862
- assert_equal [tagging], post.taggings
1863
- end
1864
-
1865
- def test_with_polymorphic_has_many_with_custom_columns_name
1866
- post = Post.create! :title => 'foo', :body => 'bar'
1867
- image = Image.create!
1868
-
1869
- post.images << image
1870
-
1871
- assert_equal [image], post.images
1872
- end
1873
-
1874
- def test_build_with_polymorphic_has_many_does_not_allow_to_override_type_and_id
1875
- welcome = posts(:welcome)
1876
- tagging = welcome.taggings.build(:taggable_id => 99, :taggable_type => 'ShouldNotChange')
1877
-
1878
- assert_equal welcome.id, tagging.taggable_id
1879
- assert_equal 'Post', tagging.taggable_type
1880
- end
1881
-
1882
- def test_dont_call_save_callbacks_twice_on_has_many
1883
- firm = companies(:first_firm)
1884
- contract = firm.contracts.create!
1885
-
1886
- assert_equal 1, contract.hi_count
1887
- assert_equal 1, contract.bye_count
1888
- end
1889
-
1890
- def test_association_attributes_are_available_to_after_initialize
1891
- car = Car.create(:name => 'honda')
1892
- bulb = car.bulbs.build
1893
-
1894
- assert_equal car.id, bulb.attributes_after_initialize['car_id']
1895
- end
1896
-
1897
- def test_attributes_are_set_when_initialized_from_has_many_null_relationship
1898
- car = Car.new name: 'honda'
1899
- bulb = car.bulbs.where(name: 'headlight').first_or_initialize
1900
- assert_equal 'headlight', bulb.name
1901
- end
1902
-
1903
- def test_attributes_are_set_when_initialized_from_polymorphic_has_many_null_relationship
1904
- post = Post.new title: 'title', body: 'bar'
1905
- tag = Tag.create!(name: 'foo')
1906
-
1907
- tagging = post.taggings.where(tag: tag).first_or_initialize
1908
-
1909
- assert_equal tag.id, tagging.tag_id
1910
- assert_equal 'Post', tagging.taggable_type
1911
- end
1912
-
1913
- def test_replace
1914
- car = Car.create(:name => 'honda')
1915
- bulb1 = car.bulbs.create
1916
- bulb2 = Bulb.create
1917
-
1918
- assert_equal [bulb1], car.bulbs
1919
- car.bulbs.replace([bulb2])
1920
- assert_equal [bulb2], car.bulbs
1921
- assert_equal [bulb2], car.reload.bulbs
1922
- end
1923
-
1924
- def test_replace_returns_target
1925
- car = Car.create(:name => 'honda')
1926
- bulb1 = car.bulbs.create
1927
- bulb2 = car.bulbs.create
1928
- bulb3 = Bulb.create
1929
-
1930
- assert_equal [bulb1, bulb2], car.bulbs
1931
- result = car.bulbs.replace([bulb3, bulb1])
1932
- assert_equal [bulb1, bulb3], car.bulbs
1933
- assert_equal [bulb1, bulb3], result
1934
- end
1935
-
1936
- def test_collection_association_with_private_kernel_method
1937
- firm = companies(:first_firm)
1938
- assert_equal [accounts(:signals37)], firm.accounts.open
1939
- end
1940
-
1941
- test "first_or_initialize adds the record to the association" do
1942
- firm = Firm.create! name: 'omg'
1943
- client = firm.clients_of_firm.first_or_initialize
1944
- assert_equal [client], firm.clients_of_firm
1945
- end
1946
-
1947
- test "first_or_create adds the record to the association" do
1948
- firm = Firm.create! name: 'omg'
1949
- firm.clients_of_firm.load_target
1950
- client = firm.clients_of_firm.first_or_create name: 'lol'
1951
- assert_equal [client], firm.clients_of_firm
1952
- assert_equal [client], firm.reload.clients_of_firm
1953
- end
1954
-
1955
- test "delete_all, when not loaded, doesn't load the records" do
1956
- post = posts(:welcome)
1957
-
1958
- assert post.taggings_with_delete_all.count > 0
1959
- assert !post.taggings_with_delete_all.loaded?
1960
-
1961
- # 2 queries: one DELETE and another to update the counter cache
1962
- assert_queries(2) do
1963
- post.taggings_with_delete_all.delete_all
1964
- end
1965
- end
1966
-
1967
- test "has many associations on new records use null relations" do
1968
- post = Post.new
1969
-
1970
- assert_no_queries(ignore_none: false) do
1971
- assert_equal [], post.comments
1972
- assert_equal [], post.comments.where(body: 'omg')
1973
- assert_equal [], post.comments.pluck(:body)
1974
- assert_equal 0, post.comments.sum(:id)
1975
- assert_equal 0, post.comments.count
1976
- end
1977
- end
1978
-
1979
- test "collection proxy respects default scope" do
1980
- author = authors(:mary)
1981
- assert !author.first_posts.exists?
1982
- end
1983
-
1984
- test "association with extend option" do
1985
- post = posts(:welcome)
1986
- assert_equal "lifo", post.comments_with_extend.author
1987
- assert_equal "hello", post.comments_with_extend.greeting
1988
- end
1989
-
1990
- test "association with extend option with multiple extensions" do
1991
- post = posts(:welcome)
1992
- assert_equal "lifo", post.comments_with_extend_2.author
1993
- assert_equal "hello", post.comments_with_extend_2.greeting
1994
- end
1995
-
1996
- test "delete record with complex joins" do
1997
- david = authors(:david)
1998
-
1999
- post = david.posts.first
2000
- post.type = 'PostWithSpecialCategorization'
2001
- post.save
2002
-
2003
- categorization = post.categorizations.first
2004
- categorization.special = true
2005
- categorization.save
2006
-
2007
- assert_not_equal [], david.posts_with_special_categorizations
2008
- david.posts_with_special_categorizations = []
2009
- assert_equal [], david.posts_with_special_categorizations
2010
- end
2011
-
2012
- test "does not duplicate associations when used with natural primary keys" do
2013
- speedometer = Speedometer.create!(id: '4')
2014
- speedometer.minivans.create!(minivan_id: 'a-van-red' ,name: 'a van', color: 'red')
2015
-
2016
- assert_equal 1, speedometer.minivans.to_a.size, "Only one association should be present:\n#{speedometer.minivans.to_a}"
2017
- assert_equal 1, speedometer.reload.minivans.to_a.size
2018
- end
2019
-
2020
- test "can unscope the default scope of the associated model" do
2021
- car = Car.create!
2022
- bulb1 = Bulb.create! name: "defaulty", car: car
2023
- bulb2 = Bulb.create! name: "other", car: car
2024
-
2025
- assert_equal [bulb1], car.bulbs
2026
- assert_equal [bulb1, bulb2], car.all_bulbs.sort_by(&:id)
2027
- end
2028
-
2029
- test "can unscope and where the default scope of the associated model" do
2030
- Car.has_many :other_bulbs, -> { unscope(where: [:name]).where(name: 'other') }, class_name: "Bulb"
2031
- car = Car.create!
2032
- bulb1 = Bulb.create! name: "defaulty", car: car
2033
- bulb2 = Bulb.create! name: "other", car: car
2034
-
2035
- assert_equal [bulb1], car.bulbs
2036
- assert_equal [bulb2], car.other_bulbs
2037
- end
2038
-
2039
- test "can rewhere the default scope of the associated model" do
2040
- Car.has_many :old_bulbs, -> { rewhere(name: 'old') }, class_name: "Bulb"
2041
- car = Car.create!
2042
- bulb1 = Bulb.create! name: "defaulty", car: car
2043
- bulb2 = Bulb.create! name: "old", car: car
2044
-
2045
- assert_equal [bulb1], car.bulbs
2046
- assert_equal [bulb2], car.old_bulbs
2047
- end
2048
-
2049
- test 'unscopes the default scope of associated model when used with include' do
2050
- car = Car.create!
2051
- bulb = Bulb.create! name: "other", car: car
2052
-
2053
- assert_equal bulb, Car.find(car.id).all_bulbs.first
2054
- assert_equal bulb, Car.includes(:all_bulbs).find(car.id).all_bulbs.first
2055
- end
2056
-
2057
- test "raises RecordNotDestroyed when replaced child can't be destroyed" do
2058
- car = Car.create!
2059
- original_child = FailedBulb.create!(car: car)
2060
-
2061
- error = assert_raise(ActiveRecord::RecordNotDestroyed) do
2062
- car.failed_bulbs = [FailedBulb.create!]
2063
- end
2064
-
2065
- assert_equal [original_child], car.reload.failed_bulbs
2066
- assert_equal "Failed to destroy the record", error.message
2067
- end
2068
-
2069
- test 'updates counter cache when default scope is given' do
2070
- topic = DefaultRejectedTopic.create approved: true
2071
-
2072
- assert_difference "topic.reload.replies_count", 1 do
2073
- topic.approved_replies.create!
2074
- end
2075
- end
2076
-
2077
- test 'dangerous association name raises ArgumentError' do
2078
- [:errors, 'errors', :save, 'save'].each do |name|
2079
- assert_raises(ArgumentError, "Association #{name} should not be allowed") do
2080
- Class.new(ActiveRecord::Base) do
2081
- has_many name
2082
- end
2083
- end
2084
- end
2085
- end
2086
-
2087
- test 'passes custom context validation to validate children' do
2088
- pirate = FamousPirate.new
2089
- pirate.famous_ships << ship = FamousShip.new
2090
-
2091
- assert pirate.valid?
2092
- assert_not pirate.valid?(:conference)
2093
- assert_equal "can't be blank", ship.errors[:name].first
2094
- end
2095
-
2096
- test 'association with instance dependent scope' do
2097
- bob = authors(:bob)
2098
- Post.create!(title: "signed post by bob", body: "stuff", author: authors(:bob))
2099
- Post.create!(title: "anonymous post", body: "more stuff", author: authors(:bob))
2100
- assert_equal ["misc post by bob", "other post by bob",
2101
- "signed post by bob"], bob.posts_with_signature.map(&:title).sort
2102
-
2103
- assert_equal [], authors(:david).posts_with_signature.map(&:title)
2104
- end
2105
-
2106
- test 'associations autosaves when object is already persited' do
2107
- bulb = Bulb.create!
2108
- tyre = Tyre.create!
2109
-
2110
- car = Car.create! do |c|
2111
- c.bulbs << bulb
2112
- c.tyres << tyre
2113
- end
2114
-
2115
- assert_equal 1, car.bulbs.count
2116
- assert_equal 1, car.tyres.count
2117
- end
2118
-
2119
- test 'associations replace in memory when records have the same id' do
2120
- bulb = Bulb.create!
2121
- car = Car.create!(bulbs: [bulb])
2122
-
2123
- new_bulb = Bulb.find(bulb.id)
2124
- new_bulb.name = "foo"
2125
- car.bulbs = [new_bulb]
2126
-
2127
- assert_equal "foo", car.bulbs.first.name
2128
- end
2129
-
2130
- test 'in memory replacement executes no queries' do
2131
- bulb = Bulb.create!
2132
- car = Car.create!(bulbs: [bulb])
2133
-
2134
- new_bulb = Bulb.find(bulb.id)
2135
-
2136
- assert_no_queries do
2137
- car.bulbs = [new_bulb]
2138
- end
2139
- end
2140
-
2141
- test 'in memory replacements do not execute callbacks' do
2142
- raise_after_add = false
2143
- klass = Class.new(ActiveRecord::Base) do
2144
- self.table_name = :cars
2145
- has_many :bulbs, after_add: proc { raise if raise_after_add }
2146
-
2147
- def self.name
2148
- "Car"
2149
- end
2150
- end
2151
- bulb = Bulb.create!
2152
- car = klass.create!(bulbs: [bulb])
2153
-
2154
- new_bulb = Bulb.find(bulb.id)
2155
- raise_after_add = true
2156
-
2157
- assert_nothing_raised do
2158
- car.bulbs = [new_bulb]
2159
- end
2160
- end
2161
-
2162
- test 'in memory replacements sets inverse instance' do
2163
- bulb = Bulb.create!
2164
- car = Car.create!(bulbs: [bulb])
2165
-
2166
- new_bulb = Bulb.find(bulb.id)
2167
- car.bulbs = [new_bulb]
2168
-
2169
- assert_same car, new_bulb.car
2170
- end
2171
-
2172
- test 'in memory replacement maintains order' do
2173
- first_bulb = Bulb.create!
2174
- second_bulb = Bulb.create!
2175
- car = Car.create!(bulbs: [first_bulb, second_bulb])
2176
-
2177
- same_bulb = Bulb.find(first_bulb.id)
2178
- car.bulbs = [second_bulb, same_bulb]
2179
-
2180
- assert_equal [first_bulb, second_bulb], car.bulbs
2181
- end
2182
- end
1
+ require "cases/helper"
2
+ require 'models/developer'
3
+ require 'models/computer'
4
+ require 'models/project'
5
+ require 'models/company'
6
+ require 'models/contract'
7
+ require 'models/topic'
8
+ require 'models/reply'
9
+ require 'models/category'
10
+ require 'models/image'
11
+ require 'models/post'
12
+ require 'models/author'
13
+ require 'models/essay'
14
+ require 'models/comment'
15
+ require 'models/person'
16
+ require 'models/reader'
17
+ require 'models/tagging'
18
+ require 'models/tag'
19
+ require 'models/invoice'
20
+ require 'models/line_item'
21
+ require 'models/car'
22
+ require 'models/bulb'
23
+ require 'models/engine'
24
+ require 'models/categorization'
25
+ require 'models/minivan'
26
+ require 'models/speedometer'
27
+ require 'models/reference'
28
+ require 'models/job'
29
+ require 'models/college'
30
+ require 'models/student'
31
+ require 'models/pirate'
32
+ require 'models/ship'
33
+ require 'models/ship_part'
34
+ require 'models/treasure'
35
+ require 'models/parrot'
36
+ require 'models/tyre'
37
+ require 'models/subscriber'
38
+ require 'models/subscription'
39
+ require 'models/zine'
40
+ require 'models/interest'
41
+
42
+ class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCase
43
+ fixtures :authors, :posts, :comments
44
+
45
+ def test_should_generate_valid_sql
46
+ author = authors(:david)
47
+ # this can fail on adapters which require ORDER BY expressions to be included in the SELECT expression
48
+ # if the reorder clauses are not correctly handled
49
+ assert author.posts_with_comments_sorted_by_comment_id.where('comments.id > 0').reorder('posts.comments_count DESC', 'posts.tags_count DESC').last
50
+ end
51
+ end
52
+
53
+ class HasManyAssociationsTestPrimaryKeys < ActiveRecord::TestCase
54
+ fixtures :authors, :essays, :subscribers, :subscriptions, :people
55
+
56
+ def test_custom_primary_key_on_new_record_should_fetch_with_query
57
+ subscriber = Subscriber.new(nick: 'webster132')
58
+ assert !subscriber.subscriptions.loaded?
59
+
60
+ assert_queries 1 do
61
+ assert_equal 2, subscriber.subscriptions.size
62
+ end
63
+
64
+ assert_equal Subscription.where(subscriber_id: "webster132"), subscriber.subscriptions
65
+ end
66
+
67
+ def test_association_primary_key_on_new_record_should_fetch_with_query
68
+ author = Author.new(:name => "David")
69
+ assert !author.essays.loaded?
70
+
71
+ assert_queries 1 do
72
+ assert_equal 1, author.essays.size
73
+ end
74
+
75
+ assert_equal Essay.where(writer_id: "David"), author.essays
76
+ end
77
+
78
+ def test_has_many_custom_primary_key
79
+ david = authors(:david)
80
+ assert_equal Essay.where(writer_id: "David"), david.essays
81
+ end
82
+
83
+ def test_ids_on_unloaded_association_with_custom_primary_key
84
+ david = people(:david)
85
+ assert_equal Essay.where(writer_id: "David").pluck(:id), david.essay_ids
86
+ end
87
+
88
+ def test_ids_on_loaded_association_with_custom_primary_key
89
+ david = people(:david)
90
+ david.essays.load
91
+ assert_equal Essay.where(writer_id: "David").pluck(:id), david.essay_ids
92
+ end
93
+
94
+ def test_has_many_assignment_with_custom_primary_key
95
+ david = people(:david)
96
+
97
+ assert_equal ["A Modest Proposal"], david.essays.map(&:name)
98
+ david.essays = [Essay.create!(name: "Remote Work" )]
99
+ assert_equal ["Remote Work"], david.essays.map(&:name)
100
+ end
101
+
102
+ def test_blank_custom_primary_key_on_new_record_should_not_run_queries
103
+ author = Author.new
104
+ assert !author.essays.loaded?
105
+
106
+ assert_queries 0 do
107
+ assert_equal 0, author.essays.size
108
+ end
109
+ end
110
+ end
111
+
112
+ class HasManyAssociationsTest < ActiveRecord::TestCase
113
+ fixtures :accounts, :categories, :companies, :developers, :projects,
114
+ :developers_projects, :topics, :authors, :comments,
115
+ :posts, :readers, :taggings, :cars, :jobs, :tags,
116
+ :categorizations, :zines, :interests
117
+
118
+ def setup
119
+ Client.destroyed_client_ids.clear
120
+ end
121
+
122
+ def test_sti_subselect_count
123
+ tag = Tag.first
124
+ len = Post.tagged_with(tag.id).limit(10).size
125
+ assert_operator len, :>, 0
126
+ end
127
+
128
+ def test_anonymous_has_many
129
+ developer = Class.new(ActiveRecord::Base) {
130
+ self.table_name = 'developers'
131
+ dev = self
132
+
133
+ developer_project = Class.new(ActiveRecord::Base) {
134
+ self.table_name = 'developers_projects'
135
+ belongs_to :developer, :anonymous_class => dev
136
+ }
137
+ has_many :developer_projects, :anonymous_class => developer_project, :foreign_key => 'developer_id'
138
+ }
139
+ dev = developer.first
140
+ named = Developer.find(dev.id)
141
+ assert_operator dev.developer_projects.count, :>, 0
142
+ assert_equal named.projects.map(&:id).sort,
143
+ dev.developer_projects.map(&:project_id).sort
144
+ end
145
+
146
+ def test_default_scope_on_relations_is_not_cached
147
+ counter = 0
148
+ posts = Class.new(ActiveRecord::Base) {
149
+ self.table_name = 'posts'
150
+ self.inheritance_column = 'not_there'
151
+ post = self
152
+
153
+ comments = Class.new(ActiveRecord::Base) {
154
+ self.table_name = 'comments'
155
+ self.inheritance_column = 'not_there'
156
+ belongs_to :post, :anonymous_class => post
157
+ default_scope -> {
158
+ counter += 1
159
+ where("id = :inc", :inc => counter)
160
+ }
161
+ }
162
+ has_many :comments, :anonymous_class => comments, :foreign_key => 'post_id'
163
+ }
164
+ assert_equal 0, counter
165
+ post = posts.first
166
+ assert_equal 0, counter
167
+ sql = capture_sql { post.comments.to_a }
168
+ post.comments.reset
169
+ assert_not_equal sql, capture_sql { post.comments.to_a }
170
+ end
171
+
172
+ def test_has_many_build_with_options
173
+ college = College.create(name: 'UFMT')
174
+ Student.create(active: true, college_id: college.id, name: 'Sarah')
175
+
176
+ assert_equal college.students, Student.where(active: true, college_id: college.id)
177
+ end
178
+
179
+ def test_add_record_to_collection_should_change_its_updated_at
180
+ ship = Ship.create(name: 'dauntless')
181
+ part = ShipPart.create(name: 'cockpit')
182
+ updated_at = part.updated_at
183
+
184
+ travel(1.second) do
185
+ ship.parts << part
186
+ end
187
+
188
+ assert_equal part.ship, ship
189
+ assert_not_equal part.updated_at, updated_at
190
+ end
191
+
192
+ def test_clear_collection_should_not_change_updated_at
193
+ # GH#17161: .clear calls delete_all (and returns the association),
194
+ # which is intended to not touch associated objects's updated_at field
195
+ ship = Ship.create(name: 'dauntless')
196
+ part = ShipPart.create(name: 'cockpit', ship_id: ship.id)
197
+
198
+ ship.parts.clear
199
+ part.reload
200
+
201
+ assert_equal nil, part.ship
202
+ assert !part.updated_at_changed?
203
+ end
204
+
205
+ def test_create_from_association_should_respect_default_scope
206
+ car = Car.create(:name => 'honda')
207
+ assert_equal 'honda', car.name
208
+
209
+ bulb = Bulb.create
210
+ assert_equal 'defaulty', bulb.name
211
+
212
+ bulb = car.bulbs.build
213
+ assert_equal 'defaulty', bulb.name
214
+
215
+ bulb = car.bulbs.create
216
+ assert_equal 'defaulty', bulb.name
217
+ end
218
+
219
+ def test_build_and_create_from_association_should_respect_passed_attributes_over_default_scope
220
+ car = Car.create(name: 'honda')
221
+
222
+ bulb = car.bulbs.build(name: 'exotic')
223
+ assert_equal 'exotic', bulb.name
224
+
225
+ bulb = car.bulbs.create(name: 'exotic')
226
+ assert_equal 'exotic', bulb.name
227
+
228
+ bulb = car.awesome_bulbs.build(frickinawesome: false)
229
+ assert_equal false, bulb.frickinawesome
230
+
231
+ bulb = car.awesome_bulbs.create(frickinawesome: false)
232
+ assert_equal false, bulb.frickinawesome
233
+ end
234
+
235
+ def test_build_from_association_should_respect_scope
236
+ author = Author.new
237
+
238
+ post = author.thinking_posts.build
239
+ assert_equal 'So I was thinking', post.title
240
+ end
241
+
242
+ def test_create_from_association_with_nil_values_should_work
243
+ car = Car.create(:name => 'honda')
244
+
245
+ bulb = car.bulbs.new(nil)
246
+ assert_equal 'defaulty', bulb.name
247
+
248
+ bulb = car.bulbs.build(nil)
249
+ assert_equal 'defaulty', bulb.name
250
+
251
+ bulb = car.bulbs.create(nil)
252
+ assert_equal 'defaulty', bulb.name
253
+ end
254
+
255
+ def test_do_not_call_callbacks_for_delete_all
256
+ car = Car.create(:name => 'honda')
257
+ car.funky_bulbs.create!
258
+ assert_nothing_raised { car.reload.funky_bulbs.delete_all }
259
+ assert_equal 0, Bulb.count, "bulbs should have been deleted using :delete_all strategy"
260
+ end
261
+
262
+ def test_delete_all_on_association_is_the_same_as_not_loaded
263
+ author = authors :david
264
+ author.thinking_posts.create!(:body => "test")
265
+ author.reload
266
+ expected_sql = capture_sql { author.thinking_posts.delete_all }
267
+
268
+ author.thinking_posts.create!(:body => "test")
269
+ author.reload
270
+ author.thinking_posts.inspect
271
+ loaded_sql = capture_sql { author.thinking_posts.delete_all }
272
+ assert_equal(expected_sql, loaded_sql)
273
+ end
274
+
275
+ def test_delete_all_on_association_with_nil_dependency_is_the_same_as_not_loaded
276
+ author = authors :david
277
+ author.posts.create!(:title => "test", :body => "body")
278
+ author.reload
279
+ expected_sql = capture_sql { author.posts.delete_all }
280
+
281
+ author.posts.create!(:title => "test", :body => "body")
282
+ author.reload
283
+ author.posts.to_a
284
+ loaded_sql = capture_sql { author.posts.delete_all }
285
+ assert_equal(expected_sql, loaded_sql)
286
+ end
287
+
288
+ def test_building_the_associated_object_with_implicit_sti_base_class
289
+ firm = DependentFirm.new
290
+ company = firm.companies.build
291
+ assert_kind_of Company, company, "Expected #{company.class} to be a Company"
292
+ end
293
+
294
+ def test_building_the_associated_object_with_explicit_sti_base_class
295
+ firm = DependentFirm.new
296
+ company = firm.companies.build(:type => "Company")
297
+ assert_kind_of Company, company, "Expected #{company.class} to be a Company"
298
+ end
299
+
300
+ def test_building_the_associated_object_with_sti_subclass
301
+ firm = DependentFirm.new
302
+ company = firm.companies.build(:type => "Client")
303
+ assert_kind_of Client, company, "Expected #{company.class} to be a Client"
304
+ end
305
+
306
+ def test_building_the_associated_object_with_an_invalid_type
307
+ firm = DependentFirm.new
308
+ assert_raise(ActiveRecord::SubclassNotFound) { firm.companies.build(:type => "Invalid") }
309
+ end
310
+
311
+ def test_building_the_associated_object_with_an_unrelated_type
312
+ firm = DependentFirm.new
313
+ assert_raise(ActiveRecord::SubclassNotFound) { firm.companies.build(:type => "Account") }
314
+ end
315
+
316
+ test "building the association with an array" do
317
+ speedometer = Speedometer.new(speedometer_id: "a")
318
+ data = [{name: "first"}, {name: "second"}]
319
+ speedometer.minivans.build(data)
320
+
321
+ assert_equal 2, speedometer.minivans.size
322
+ assert speedometer.save
323
+ assert_equal ["first", "second"], speedometer.reload.minivans.map(&:name)
324
+ end
325
+
326
+ def test_association_keys_bypass_attribute_protection
327
+ car = Car.create(:name => 'honda')
328
+
329
+ bulb = car.bulbs.new
330
+ assert_equal car.id, bulb.car_id
331
+
332
+ bulb = car.bulbs.new :car_id => car.id + 1
333
+ assert_equal car.id, bulb.car_id
334
+
335
+ bulb = car.bulbs.build
336
+ assert_equal car.id, bulb.car_id
337
+
338
+ bulb = car.bulbs.build :car_id => car.id + 1
339
+ assert_equal car.id, bulb.car_id
340
+
341
+ bulb = car.bulbs.create
342
+ assert_equal car.id, bulb.car_id
343
+
344
+ bulb = car.bulbs.create :car_id => car.id + 1
345
+ assert_equal car.id, bulb.car_id
346
+ end
347
+
348
+ def test_association_protect_foreign_key
349
+ invoice = Invoice.create
350
+
351
+ line_item = invoice.line_items.new
352
+ assert_equal invoice.id, line_item.invoice_id
353
+
354
+ line_item = invoice.line_items.new :invoice_id => invoice.id + 1
355
+ assert_equal invoice.id, line_item.invoice_id
356
+
357
+ line_item = invoice.line_items.build
358
+ assert_equal invoice.id, line_item.invoice_id
359
+
360
+ line_item = invoice.line_items.build :invoice_id => invoice.id + 1
361
+ assert_equal invoice.id, line_item.invoice_id
362
+
363
+ line_item = invoice.line_items.create
364
+ assert_equal invoice.id, line_item.invoice_id
365
+
366
+ line_item = invoice.line_items.create :invoice_id => invoice.id + 1
367
+ assert_equal invoice.id, line_item.invoice_id
368
+ end
369
+
370
+ # When creating objects on the association, we must not do it within a scope (even though it
371
+ # would be convenient), because this would cause that scope to be applied to any callbacks etc.
372
+ def test_build_and_create_should_not_happen_within_scope
373
+ car = cars(:honda)
374
+ scope = car.foo_bulbs.where_values_hash
375
+
376
+ bulb = car.foo_bulbs.build
377
+ assert_not_equal scope, bulb.scope_after_initialize.where_values_hash
378
+
379
+ bulb = car.foo_bulbs.create
380
+ assert_not_equal scope, bulb.scope_after_initialize.where_values_hash
381
+
382
+ bulb = car.foo_bulbs.create!
383
+ assert_not_equal scope, bulb.scope_after_initialize.where_values_hash
384
+ end
385
+
386
+ def test_no_sql_should_be_fired_if_association_already_loaded
387
+ Car.create(:name => 'honda')
388
+ bulbs = Car.first.bulbs
389
+ bulbs.to_a # to load all instances of bulbs
390
+
391
+ assert_no_queries do
392
+ bulbs.first()
393
+ bulbs.first({})
394
+ end
395
+
396
+ assert_no_queries do
397
+ bulbs.second()
398
+ bulbs.second({})
399
+ end
400
+
401
+ assert_no_queries do
402
+ bulbs.third()
403
+ bulbs.third({})
404
+ end
405
+
406
+ assert_no_queries do
407
+ bulbs.fourth()
408
+ bulbs.fourth({})
409
+ end
410
+
411
+ assert_no_queries do
412
+ bulbs.fifth()
413
+ bulbs.fifth({})
414
+ end
415
+
416
+ assert_no_queries do
417
+ bulbs.forty_two()
418
+ bulbs.forty_two({})
419
+ end
420
+
421
+ assert_no_queries do
422
+ bulbs.third_to_last()
423
+ bulbs.third_to_last({})
424
+ end
425
+
426
+ assert_no_queries do
427
+ bulbs.second_to_last()
428
+ bulbs.second_to_last({})
429
+ end
430
+
431
+ assert_no_queries do
432
+ bulbs.last()
433
+ bulbs.last({})
434
+ end
435
+ end
436
+
437
+ def test_create_resets_cached_counters
438
+ person = Person.create!(:first_name => 'tenderlove')
439
+ post = Post.first
440
+
441
+ assert_equal [], person.readers
442
+ assert_nil person.readers.find_by_post_id(post.id)
443
+
444
+ person.readers.create(:post_id => post.id)
445
+
446
+ assert_equal 1, person.readers.count
447
+ assert_equal 1, person.readers.length
448
+ assert_equal post, person.readers.first.post
449
+ assert_equal person, person.readers.first.person
450
+ end
451
+
452
+ def test_update_all_respects_association_scope
453
+ person = Person.new
454
+ person.first_name = 'Naruto'
455
+ person.references << Reference.new
456
+ person.id = 10
457
+ person.references
458
+ person.save!
459
+ assert_equal 1, person.references.update_all(favourite: true)
460
+ end
461
+
462
+ def test_exists_respects_association_scope
463
+ person = Person.new
464
+ person.first_name = 'Sasuke'
465
+ person.references << Reference.new
466
+ person.id = 10
467
+ person.references
468
+ person.save!
469
+ assert_predicate person.references, :exists?
470
+ end
471
+
472
+ def force_signal37_to_load_all_clients_of_firm
473
+ companies(:first_firm).clients_of_firm.each {|f| }
474
+ end
475
+
476
+ # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
477
+ def test_counting_with_counter_sql
478
+ assert_equal 3, Firm.all.merge!(:order => "id").first.clients.count
479
+ end
480
+
481
+ def test_counting
482
+ assert_equal 3, Firm.all.merge!(:order => "id").first.plain_clients.count
483
+ end
484
+
485
+ def test_counting_with_single_hash
486
+ assert_equal 1, Firm.all.merge!(:order => "id").first.plain_clients.where(:name => "Microsoft").count
487
+ end
488
+
489
+ def test_counting_with_column_name_and_hash
490
+ assert_equal 3, Firm.all.merge!(:order => "id").first.plain_clients.count(:name)
491
+ end
492
+
493
+ def test_counting_with_association_limit
494
+ firm = companies(:first_firm)
495
+ assert_equal firm.limited_clients.length, firm.limited_clients.size
496
+ assert_equal firm.limited_clients.length, firm.limited_clients.count
497
+ end
498
+
499
+ def test_finding
500
+ assert_equal 3, Firm.all.merge!(:order => "id").first.clients.length
501
+ end
502
+
503
+ def test_finding_array_compatibility
504
+ assert_equal 3, Firm.order(:id).find{|f| f.id > 0}.clients.length
505
+ end
506
+
507
+ def test_find_many_with_merged_options
508
+ assert_equal 1, companies(:first_firm).limited_clients.size
509
+ assert_equal 1, companies(:first_firm).limited_clients.to_a.size
510
+ assert_equal 3, companies(:first_firm).limited_clients.limit(nil).to_a.size
511
+ end
512
+
513
+ def test_find_should_append_to_association_order
514
+ ordered_clients = companies(:first_firm).clients_sorted_desc.order('companies.id')
515
+ assert_equal ['id DESC', 'companies.id'], ordered_clients.order_values
516
+ end
517
+
518
+ def test_dynamic_find_should_respect_association_order
519
+ assert_equal companies(:another_first_firm_client), companies(:first_firm).clients_sorted_desc.where("type = 'Client'").first
520
+ assert_equal companies(:another_first_firm_client), companies(:first_firm).clients_sorted_desc.find_by_type('Client')
521
+ end
522
+
523
+ def test_taking
524
+ posts(:other_by_bob).destroy
525
+ assert_equal posts(:misc_by_bob), authors(:bob).posts.take
526
+ assert_equal posts(:misc_by_bob), authors(:bob).posts.take!
527
+ authors(:bob).posts.to_a
528
+ assert_equal posts(:misc_by_bob), authors(:bob).posts.take
529
+ assert_equal posts(:misc_by_bob), authors(:bob).posts.take!
530
+ end
531
+
532
+ def test_taking_not_found
533
+ authors(:bob).posts.delete_all
534
+ assert_raise(ActiveRecord::RecordNotFound) { authors(:bob).posts.take! }
535
+ authors(:bob).posts.to_a
536
+ assert_raise(ActiveRecord::RecordNotFound) { authors(:bob).posts.take! }
537
+ end
538
+
539
+ def test_taking_with_a_number
540
+ # taking from unloaded Relation
541
+ bob = Author.find(authors(:bob).id)
542
+ assert_equal [posts(:misc_by_bob)], bob.posts.take(1)
543
+ bob = Author.find(authors(:bob).id)
544
+ assert_equal [posts(:misc_by_bob), posts(:other_by_bob)], bob.posts.take(2)
545
+
546
+ # taking from loaded Relation
547
+ bob.posts.to_a
548
+ assert_equal [posts(:misc_by_bob)], authors(:bob).posts.take(1)
549
+ assert_equal [posts(:misc_by_bob), posts(:other_by_bob)], authors(:bob).posts.take(2)
550
+ end
551
+
552
+ def test_taking_with_inverse_of
553
+ interests(:woodsmanship).destroy
554
+ interests(:survival).destroy
555
+
556
+ zine = zines(:going_out)
557
+ interest = zine.interests.take
558
+ assert_equal interests(:hunting), interest
559
+ assert_same zine, interest.zine
560
+ end
561
+
562
+ def test_cant_save_has_many_readonly_association
563
+ authors(:david).readonly_comments.each { |c| assert_raise(ActiveRecord::ReadOnlyRecord) { c.save! } }
564
+ authors(:david).readonly_comments.each { |c| assert c.readonly? }
565
+ end
566
+
567
+ def test_finding_default_orders
568
+ assert_equal "Summit", Firm.all.merge!(:order => "id").first.clients.first.name
569
+ end
570
+
571
+ def test_finding_with_different_class_name_and_order
572
+ assert_equal "Apex", Firm.all.merge!(:order => "id").first.clients_sorted_desc.first.name
573
+ end
574
+
575
+ def test_finding_with_foreign_key
576
+ assert_equal "Microsoft", Firm.all.merge!(:order => "id").first.clients_of_firm.first.name
577
+ end
578
+
579
+ def test_finding_with_condition
580
+ assert_equal "Microsoft", Firm.all.merge!(:order => "id").first.clients_like_ms.first.name
581
+ end
582
+
583
+ def test_finding_with_condition_hash
584
+ assert_equal "Microsoft", Firm.all.merge!(:order => "id").first.clients_like_ms_with_hash_conditions.first.name
585
+ end
586
+
587
+ def test_finding_using_primary_key
588
+ assert_equal "Summit", Firm.all.merge!(:order => "id").first.clients_using_primary_key.first.name
589
+ end
590
+
591
+ def test_update_all_on_association_accessed_before_save
592
+ firm = Firm.new(name: "Firm")
593
+ firm.clients << Client.first
594
+ firm.save!
595
+ assert_equal firm.clients.count, firm.clients.update_all(description: "Great!")
596
+ end
597
+
598
+ def test_update_all_on_association_accessed_before_save_with_explicit_foreign_key
599
+ firm = Firm.new(name: "Firm", id: 100)
600
+ firm.clients << Client.first
601
+ firm.save!
602
+ assert_equal firm.clients.count, firm.clients.update_all(description: "Great!")
603
+ end
604
+
605
+ def test_belongs_to_sanity
606
+ c = Client.new
607
+ assert_nil c.firm, "belongs_to failed sanity check on new object"
608
+ end
609
+
610
+ def test_find_ids
611
+ firm = Firm.all.merge!(:order => "id").first
612
+
613
+ assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find }
614
+
615
+ client = firm.clients.find(2)
616
+ assert_kind_of Client, client
617
+
618
+ client_ary = firm.clients.find([2])
619
+ assert_kind_of Array, client_ary
620
+ assert_equal client, client_ary.first
621
+
622
+ client_ary = firm.clients.find(2, 3)
623
+ assert_kind_of Array, client_ary
624
+ assert_equal 2, client_ary.size
625
+ assert_equal client, client_ary.first
626
+
627
+ assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(2, 99) }
628
+ end
629
+
630
+ def test_find_one_message_on_primary_key
631
+ firm = Firm.all.merge!(order: "id").first
632
+
633
+ e = assert_raises(ActiveRecord::RecordNotFound) do
634
+ firm.clients.find(0)
635
+ end
636
+ assert_equal 0, e.id
637
+ assert_equal "id", e.primary_key
638
+ assert_equal "Client", e.model
639
+ assert_match (/\ACouldn't find Client with 'id'=0/), e.message
640
+ end
641
+
642
+ def test_find_ids_and_inverse_of
643
+ force_signal37_to_load_all_clients_of_firm
644
+
645
+ firm = companies(:first_firm)
646
+ client = firm.clients_of_firm.find(3)
647
+ assert_kind_of Client, client
648
+
649
+ client_ary = firm.clients_of_firm.find([3])
650
+ assert_kind_of Array, client_ary
651
+ assert_equal client, client_ary.first
652
+ end
653
+
654
+ def test_find_all
655
+ firm = Firm.all.merge!(:order => "id").first
656
+ assert_equal 3, firm.clients.where("#{QUOTED_TYPE} = 'Client'").to_a.length
657
+ assert_equal 1, firm.clients.where("name = 'Summit'").to_a.length
658
+ end
659
+
660
+ def test_find_each
661
+ firm = companies(:first_firm)
662
+
663
+ assert ! firm.clients.loaded?
664
+
665
+ assert_queries(4) do
666
+ firm.clients.find_each(:batch_size => 1) {|c| assert_equal firm.id, c.firm_id }
667
+ end
668
+
669
+ assert ! firm.clients.loaded?
670
+ end
671
+
672
+ def test_find_each_with_conditions
673
+ firm = companies(:first_firm)
674
+
675
+ assert_queries(2) do
676
+ firm.clients.where(name: 'Microsoft').find_each(batch_size: 1) do |c|
677
+ assert_equal firm.id, c.firm_id
678
+ assert_equal "Microsoft", c.name
679
+ end
680
+ end
681
+
682
+ assert ! firm.clients.loaded?
683
+ end
684
+
685
+ def test_find_in_batches
686
+ firm = companies(:first_firm)
687
+
688
+ assert ! firm.clients.loaded?
689
+
690
+ assert_queries(2) do
691
+ firm.clients.find_in_batches(:batch_size => 2) do |clients|
692
+ clients.each {|c| assert_equal firm.id, c.firm_id }
693
+ end
694
+ end
695
+
696
+ assert ! firm.clients.loaded?
697
+ end
698
+
699
+ def test_find_all_sanitized
700
+ # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
701
+ firm = Firm.all.merge!(:order => "id").first
702
+ summit = firm.clients.where("name = 'Summit'").to_a
703
+ assert_equal summit, firm.clients.where("name = ?", "Summit").to_a
704
+ assert_equal summit, firm.clients.where("name = :name", { :name => "Summit" }).to_a
705
+ end
706
+
707
+ def test_find_first
708
+ firm = Firm.all.merge!(:order => "id").first
709
+ client2 = Client.find(2)
710
+ assert_equal firm.clients.first, firm.clients.order("id").first
711
+ assert_equal client2, firm.clients.where("#{QUOTED_TYPE} = 'Client'").order("id").first
712
+ end
713
+
714
+ def test_find_first_sanitized
715
+ firm = Firm.all.merge!(:order => "id").first
716
+ client2 = Client.find(2)
717
+ assert_equal client2, firm.clients.merge!(:where => ["#{QUOTED_TYPE} = ?", 'Client'], :order => "id").first
718
+ assert_equal client2, firm.clients.merge!(:where => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }], :order => "id").first
719
+ end
720
+
721
+ def test_find_all_with_include_and_conditions
722
+ assert_nothing_raised do
723
+ Developer.all.merge!(:joins => :audit_logs, :where => {'audit_logs.message' => nil, :name => 'Smith'}).to_a
724
+ end
725
+ end
726
+
727
+ def test_find_in_collection
728
+ assert_equal Client.find(2).name, companies(:first_firm).clients.find(2).name
729
+ assert_raise(ActiveRecord::RecordNotFound) { companies(:first_firm).clients.find(6) }
730
+ end
731
+
732
+ def test_find_grouped
733
+ all_clients_of_firm1 = Client.all.merge!(:where => "firm_id = 1").to_a
734
+ grouped_clients_of_firm1 = Client.all.merge!(:where => "firm_id = 1", :group => "firm_id", :select => 'firm_id, count(id) as clients_count').to_a
735
+ assert_equal 3, all_clients_of_firm1.size
736
+ assert_equal 1, grouped_clients_of_firm1.size
737
+ end
738
+
739
+ def test_find_scoped_grouped
740
+ assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.size
741
+ assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.length
742
+ assert_equal 3, companies(:first_firm).clients_grouped_by_name.size
743
+ assert_equal 3, companies(:first_firm).clients_grouped_by_name.length
744
+ end
745
+
746
+ def test_find_scoped_grouped_having
747
+ assert_equal 1, authors(:david).popular_grouped_posts.length
748
+ assert_equal 0, authors(:mary).popular_grouped_posts.length
749
+ end
750
+
751
+ def test_default_select
752
+ assert_equal Comment.column_names.sort, posts(:welcome).comments.first.attributes.keys.sort
753
+ end
754
+
755
+ def test_select_query_method
756
+ assert_equal ['id', 'body'], posts(:welcome).comments.select(:id, :body).first.attributes.keys
757
+ end
758
+
759
+ def test_select_with_block
760
+ assert_equal [1], posts(:welcome).comments.select { |c| c.id == 1 }.map(&:id)
761
+ end
762
+
763
+ def test_select_without_foreign_key
764
+ assert_equal companies(:first_firm).accounts.first.credit_limit, companies(:first_firm).accounts.select(:credit_limit).first.credit_limit
765
+ end
766
+
767
+ def test_adding
768
+ force_signal37_to_load_all_clients_of_firm
769
+ natural = Client.new("name" => "Natural Company")
770
+ companies(:first_firm).clients_of_firm << natural
771
+ assert_equal 3, companies(:first_firm).clients_of_firm.size # checking via the collection
772
+ assert_equal 3, companies(:first_firm).clients_of_firm.reload.size # checking using the db
773
+ assert_equal natural, companies(:first_firm).clients_of_firm.last
774
+ end
775
+
776
+ def test_adding_using_create
777
+ first_firm = companies(:first_firm)
778
+ assert_equal 3, first_firm.plain_clients.size
779
+ first_firm.plain_clients.create(:name => "Natural Company")
780
+ assert_equal 4, first_firm.plain_clients.length
781
+ assert_equal 4, first_firm.plain_clients.size
782
+ end
783
+
784
+ def test_create_with_bang_on_has_many_when_parent_is_new_raises
785
+ error = assert_raise(ActiveRecord::RecordNotSaved) do
786
+ firm = Firm.new
787
+ firm.plain_clients.create! :name=>"Whoever"
788
+ end
789
+
790
+ assert_equal "You cannot call create unless the parent is saved", error.message
791
+ end
792
+
793
+ def test_regular_create_on_has_many_when_parent_is_new_raises
794
+ error = assert_raise(ActiveRecord::RecordNotSaved) do
795
+ firm = Firm.new
796
+ firm.plain_clients.create :name=>"Whoever"
797
+ end
798
+
799
+ assert_equal "You cannot call create unless the parent is saved", error.message
800
+ end
801
+
802
+ def test_create_with_bang_on_has_many_raises_when_record_not_saved
803
+ assert_raise(ActiveRecord::RecordInvalid) do
804
+ firm = Firm.all.merge!(:order => "id").first
805
+ firm.plain_clients.create!
806
+ end
807
+ end
808
+
809
+ def test_create_with_bang_on_habtm_when_parent_is_new_raises
810
+ error = assert_raise(ActiveRecord::RecordNotSaved) do
811
+ Developer.new("name" => "Aredridel").projects.create!
812
+ end
813
+
814
+ assert_equal "You cannot call create unless the parent is saved", error.message
815
+ end
816
+
817
+ def test_adding_a_mismatch_class
818
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << nil }
819
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << 1 }
820
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << Topic.find(1) }
821
+ end
822
+
823
+ def test_adding_a_collection
824
+ force_signal37_to_load_all_clients_of_firm
825
+ companies(:first_firm).clients_of_firm.concat([Client.new("name" => "Natural Company"), Client.new("name" => "Apple")])
826
+ assert_equal 4, companies(:first_firm).clients_of_firm.size
827
+ assert_equal 4, companies(:first_firm).clients_of_firm.reload.size
828
+ end
829
+
830
+ def test_transactions_when_adding_to_persisted
831
+ good = Client.new(:name => "Good")
832
+ bad = Client.new(:name => "Bad", :raise_on_save => true)
833
+
834
+ begin
835
+ companies(:first_firm).clients_of_firm.concat(good, bad)
836
+ rescue Client::RaisedOnSave
837
+ end
838
+
839
+ assert !companies(:first_firm).clients_of_firm.reload.include?(good)
840
+ end
841
+
842
+ def test_transactions_when_adding_to_new_record
843
+ assert_no_queries(ignore_none: false) do
844
+ firm = Firm.new
845
+ firm.clients_of_firm.concat(Client.new("name" => "Natural Company"))
846
+ end
847
+ end
848
+
849
+ def test_inverse_on_before_validate
850
+ firm = companies(:first_firm)
851
+ assert_queries(1) do
852
+ firm.clients_of_firm << Client.new("name" => "Natural Company")
853
+ end
854
+ end
855
+
856
+ def test_new_aliased_to_build
857
+ company = companies(:first_firm)
858
+ new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.new("name" => "Another Client") }
859
+ assert !company.clients_of_firm.loaded?
860
+
861
+ assert_equal "Another Client", new_client.name
862
+ assert !new_client.persisted?
863
+ assert_equal new_client, company.clients_of_firm.last
864
+ end
865
+
866
+ def test_build
867
+ company = companies(:first_firm)
868
+ new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build("name" => "Another Client") }
869
+ assert !company.clients_of_firm.loaded?
870
+
871
+ assert_equal "Another Client", new_client.name
872
+ assert !new_client.persisted?
873
+ assert_equal new_client, company.clients_of_firm.last
874
+ end
875
+
876
+ def test_collection_size_after_building
877
+ company = companies(:first_firm) # company already has one client
878
+ company.clients_of_firm.build("name" => "Another Client")
879
+ company.clients_of_firm.build("name" => "Yet Another Client")
880
+ assert_equal 4, company.clients_of_firm.size
881
+ end
882
+
883
+ def test_collection_not_empty_after_building
884
+ company = companies(:first_firm)
885
+ assert_predicate company.contracts, :empty?
886
+ company.contracts.build
887
+ assert_not_predicate company.contracts, :empty?
888
+ end
889
+
890
+ def test_collection_size_twice_for_regressions
891
+ post = posts(:thinking)
892
+ assert_equal 0, post.readers.size
893
+ # This test needs a post that has no readers, we assert it to ensure it holds,
894
+ # but need to reload the post because the very call to #size hides the bug.
895
+ post.reload
896
+ post.readers.build
897
+ size1 = post.readers.size
898
+ size2 = post.readers.size
899
+ assert_equal size1, size2
900
+ end
901
+
902
+ def test_build_many
903
+ company = companies(:first_firm)
904
+ new_clients = assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) }
905
+ assert_equal 2, new_clients.size
906
+ end
907
+
908
+ def test_build_followed_by_save_does_not_load_target
909
+ companies(:first_firm).clients_of_firm.build("name" => "Another Client")
910
+ assert companies(:first_firm).save
911
+ assert !companies(:first_firm).clients_of_firm.loaded?
912
+ end
913
+
914
+ def test_build_without_loading_association
915
+ first_topic = topics(:first)
916
+ Reply.column_names
917
+
918
+ assert_equal 1, first_topic.replies.length
919
+
920
+ assert_no_queries do
921
+ first_topic.replies.build(:title => "Not saved", :content => "Superstars")
922
+ assert_equal 2, first_topic.replies.size
923
+ end
924
+
925
+ assert_equal 2, first_topic.replies.to_ary.size
926
+ end
927
+
928
+ def test_build_via_block
929
+ company = companies(:first_firm)
930
+ new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build {|client| client.name = "Another Client" } }
931
+ assert !company.clients_of_firm.loaded?
932
+
933
+ assert_equal "Another Client", new_client.name
934
+ assert !new_client.persisted?
935
+ assert_equal new_client, company.clients_of_firm.last
936
+ end
937
+
938
+ def test_build_many_via_block
939
+ company = companies(:first_firm)
940
+ new_clients = assert_no_queries(ignore_none: false) do
941
+ company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client|
942
+ client.name = "changed"
943
+ end
944
+ end
945
+
946
+ assert_equal 2, new_clients.size
947
+ assert_equal "changed", new_clients.first.name
948
+ assert_equal "changed", new_clients.last.name
949
+ end
950
+
951
+ def test_create_without_loading_association
952
+ first_firm = companies(:first_firm)
953
+ Firm.column_names
954
+ Client.column_names
955
+
956
+ assert_equal 2, first_firm.clients_of_firm.size
957
+ first_firm.clients_of_firm.reset
958
+
959
+ assert_queries(1) do
960
+ first_firm.clients_of_firm.create(:name => "Superstars")
961
+ end
962
+
963
+ assert_equal 3, first_firm.clients_of_firm.size
964
+ end
965
+
966
+ def test_create
967
+ force_signal37_to_load_all_clients_of_firm
968
+ new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client")
969
+ assert new_client.persisted?
970
+ assert_equal new_client, companies(:first_firm).clients_of_firm.last
971
+ assert_equal new_client, companies(:first_firm).clients_of_firm.reload.last
972
+ end
973
+
974
+ def test_create_many
975
+ companies(:first_firm).clients_of_firm.create([{"name" => "Another Client"}, {"name" => "Another Client II"}])
976
+ assert_equal 4, companies(:first_firm).clients_of_firm.reload.size
977
+ end
978
+
979
+ def test_create_followed_by_save_does_not_load_target
980
+ companies(:first_firm).clients_of_firm.create("name" => "Another Client")
981
+ assert companies(:first_firm).save
982
+ assert !companies(:first_firm).clients_of_firm.loaded?
983
+ end
984
+
985
+ def test_deleting
986
+ force_signal37_to_load_all_clients_of_firm
987
+ companies(:first_firm).clients_of_firm.delete(companies(:first_firm).clients_of_firm.first)
988
+ assert_equal 1, companies(:first_firm).clients_of_firm.size
989
+ assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
990
+ end
991
+
992
+ def test_deleting_before_save
993
+ new_firm = Firm.new("name" => "A New Firm, Inc.")
994
+ new_client = new_firm.clients_of_firm.build("name" => "Another Client")
995
+ assert_equal 1, new_firm.clients_of_firm.size
996
+ new_firm.clients_of_firm.delete(new_client)
997
+ assert_equal 0, new_firm.clients_of_firm.size
998
+ end
999
+
1000
+ def test_has_many_without_counter_cache_option
1001
+ # Ship has a conventionally named `treasures_count` column, but the counter_cache
1002
+ # option is not given on the association.
1003
+ ship = Ship.create(name: 'Countless', treasures_count: 10)
1004
+
1005
+ assert_not Ship.reflect_on_association(:treasures).has_cached_counter?
1006
+
1007
+ # Count should come from sql count() of treasures rather than treasures_count attribute
1008
+ assert_equal ship.treasures.size, 0
1009
+
1010
+ assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed" do
1011
+ ship.treasures.create(name: 'Gold')
1012
+ end
1013
+
1014
+ assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed" do
1015
+ ship.treasures.destroy_all
1016
+ end
1017
+ end
1018
+
1019
+ def test_deleting_updates_counter_cache
1020
+ topic = Topic.order("id ASC").first
1021
+ assert_equal topic.replies.to_a.size, topic.replies_count
1022
+
1023
+ topic.replies.delete(topic.replies.first)
1024
+ topic.reload
1025
+ assert_equal topic.replies.to_a.size, topic.replies_count
1026
+ end
1027
+
1028
+ def test_counter_cache_updates_in_memory_after_concat
1029
+ topic = Topic.create title: "Zoom-zoom-zoom"
1030
+
1031
+ topic.replies << Reply.create(title: "re: zoom", content: "speedy quick!")
1032
+ assert_equal 1, topic.replies_count
1033
+ assert_equal 1, topic.replies.size
1034
+ assert_equal 1, topic.reload.replies.size
1035
+ end
1036
+
1037
+ def test_counter_cache_updates_in_memory_after_create
1038
+ topic = Topic.create title: "Zoom-zoom-zoom"
1039
+
1040
+ topic.replies.create!(title: "re: zoom", content: "speedy quick!")
1041
+ assert_equal 1, topic.replies_count
1042
+ assert_equal 1, topic.replies.size
1043
+ assert_equal 1, topic.reload.replies.size
1044
+ end
1045
+
1046
+ def test_counter_cache_updates_in_memory_after_create_with_array
1047
+ topic = Topic.create title: "Zoom-zoom-zoom"
1048
+
1049
+ topic.replies.create!([
1050
+ { title: "re: zoom", content: "speedy quick!" },
1051
+ { title: "re: zoom 2", content: "OMG lol!" },
1052
+ ])
1053
+ assert_equal 2, topic.replies_count
1054
+ assert_equal 2, topic.replies.size
1055
+ assert_equal 2, topic.reload.replies.size
1056
+ end
1057
+
1058
+ def test_pushing_association_updates_counter_cache
1059
+ topic = Topic.order("id ASC").first
1060
+ reply = Reply.create!
1061
+
1062
+ assert_difference "topic.reload.replies_count", 1 do
1063
+ topic.replies << reply
1064
+ end
1065
+ end
1066
+
1067
+ def test_deleting_updates_counter_cache_without_dependent_option
1068
+ post = posts(:welcome)
1069
+
1070
+ assert_difference "post.reload.tags_count", -1 do
1071
+ post.taggings.delete(post.taggings.first)
1072
+ end
1073
+ end
1074
+
1075
+ def test_deleting_updates_counter_cache_with_dependent_delete_all
1076
+ post = posts(:welcome)
1077
+ post.update_columns(taggings_with_delete_all_count: post.tags_count)
1078
+
1079
+ assert_difference "post.reload.taggings_with_delete_all_count", -1 do
1080
+ post.taggings_with_delete_all.delete(post.taggings_with_delete_all.first)
1081
+ end
1082
+ end
1083
+
1084
+ def test_deleting_updates_counter_cache_with_dependent_destroy
1085
+ post = posts(:welcome)
1086
+ post.update_columns(taggings_with_destroy_count: post.tags_count)
1087
+
1088
+ assert_difference "post.reload.taggings_with_destroy_count", -1 do
1089
+ post.taggings_with_destroy.delete(post.taggings_with_destroy.first)
1090
+ end
1091
+ end
1092
+
1093
+ def test_calling_empty_with_counter_cache
1094
+ post = posts(:welcome)
1095
+ assert_queries(0) do
1096
+ assert_not post.comments.empty?
1097
+ end
1098
+ end
1099
+
1100
+ def test_custom_named_counter_cache
1101
+ topic = topics(:first)
1102
+
1103
+ assert_difference "topic.reload.replies_count", -1 do
1104
+ topic.approved_replies.clear
1105
+ end
1106
+ end
1107
+
1108
+ def test_calling_update_attributes_on_id_changes_the_counter_cache
1109
+ topic = Topic.order("id ASC").first
1110
+ original_count = topic.replies.to_a.size
1111
+ assert_equal original_count, topic.replies_count
1112
+
1113
+ first_reply = topic.replies.first
1114
+ first_reply.update_attributes(:parent_id => nil)
1115
+ assert_equal original_count - 1, topic.reload.replies_count
1116
+
1117
+ first_reply.update_attributes(:parent_id => topic.id)
1118
+ assert_equal original_count, topic.reload.replies_count
1119
+ end
1120
+
1121
+ def test_calling_update_attributes_changing_ids_doesnt_change_counter_cache
1122
+ topic1 = Topic.find(1)
1123
+ topic2 = Topic.find(3)
1124
+ original_count1 = topic1.replies.to_a.size
1125
+ original_count2 = topic2.replies.to_a.size
1126
+
1127
+ reply1 = topic1.replies.first
1128
+ reply2 = topic2.replies.first
1129
+
1130
+ reply1.update_attributes(:parent_id => topic2.id)
1131
+ assert_equal original_count1 - 1, topic1.reload.replies_count
1132
+ assert_equal original_count2 + 1, topic2.reload.replies_count
1133
+
1134
+ reply2.update_attributes(:parent_id => topic1.id)
1135
+ assert_equal original_count1, topic1.reload.replies_count
1136
+ assert_equal original_count2, topic2.reload.replies_count
1137
+ end
1138
+
1139
+ def test_deleting_a_collection
1140
+ force_signal37_to_load_all_clients_of_firm
1141
+ companies(:first_firm).clients_of_firm.create("name" => "Another Client")
1142
+ assert_equal 3, companies(:first_firm).clients_of_firm.size
1143
+ companies(:first_firm).clients_of_firm.delete([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1], companies(:first_firm).clients_of_firm[2]])
1144
+ assert_equal 0, companies(:first_firm).clients_of_firm.size
1145
+ assert_equal 0, companies(:first_firm).clients_of_firm.reload.size
1146
+ end
1147
+
1148
+ def test_delete_all
1149
+ force_signal37_to_load_all_clients_of_firm
1150
+ companies(:first_firm).dependent_clients_of_firm.create("name" => "Another Client")
1151
+ clients = companies(:first_firm).dependent_clients_of_firm.to_a
1152
+ assert_equal 3, clients.count
1153
+
1154
+ assert_difference "Client.count", -(clients.count) do
1155
+ companies(:first_firm).dependent_clients_of_firm.delete_all
1156
+ end
1157
+ end
1158
+
1159
+ def test_delete_all_with_not_yet_loaded_association_collection
1160
+ force_signal37_to_load_all_clients_of_firm
1161
+ companies(:first_firm).clients_of_firm.create("name" => "Another Client")
1162
+ assert_equal 3, companies(:first_firm).clients_of_firm.size
1163
+ companies(:first_firm).clients_of_firm.reset
1164
+ companies(:first_firm).clients_of_firm.delete_all
1165
+ assert_equal 0, companies(:first_firm).clients_of_firm.size
1166
+ assert_equal 0, companies(:first_firm).clients_of_firm.reload.size
1167
+ end
1168
+
1169
+ def test_transaction_when_deleting_persisted
1170
+ good = Client.new(:name => "Good")
1171
+ bad = Client.new(:name => "Bad", :raise_on_destroy => true)
1172
+
1173
+ companies(:first_firm).clients_of_firm = [good, bad]
1174
+
1175
+ begin
1176
+ companies(:first_firm).clients_of_firm.destroy(good, bad)
1177
+ rescue Client::RaisedOnDestroy
1178
+ end
1179
+
1180
+ assert_equal [good, bad], companies(:first_firm).clients_of_firm.reload
1181
+ end
1182
+
1183
+ def test_transaction_when_deleting_new_record
1184
+ assert_no_queries(ignore_none: false) do
1185
+ firm = Firm.new
1186
+ client = Client.new("name" => "New Client")
1187
+ firm.clients_of_firm << client
1188
+ firm.clients_of_firm.destroy(client)
1189
+ end
1190
+ end
1191
+
1192
+ def test_clearing_an_association_collection
1193
+ firm = companies(:first_firm)
1194
+ client_id = firm.clients_of_firm.first.id
1195
+ assert_equal 2, firm.clients_of_firm.size
1196
+
1197
+ firm.clients_of_firm.clear
1198
+
1199
+ assert_equal 0, firm.clients_of_firm.size
1200
+ assert_equal 0, firm.clients_of_firm.reload.size
1201
+ assert_equal [], Client.destroyed_client_ids[firm.id]
1202
+
1203
+ # Should not be destroyed since the association is not dependent.
1204
+ assert_nothing_raised do
1205
+ assert_nil Client.find(client_id).firm
1206
+ end
1207
+ end
1208
+
1209
+ def test_clearing_updates_counter_cache
1210
+ topic = Topic.first
1211
+
1212
+ assert_difference 'topic.reload.replies_count', -1 do
1213
+ topic.replies.clear
1214
+ end
1215
+ end
1216
+
1217
+ def test_clearing_updates_counter_cache_when_inverse_counter_cache_is_a_symbol_with_dependent_destroy
1218
+ car = Car.first
1219
+ car.engines.create!
1220
+
1221
+ assert_difference 'car.reload.engines_count', -1 do
1222
+ car.engines.clear
1223
+ end
1224
+ end
1225
+
1226
+ def test_clearing_a_dependent_association_collection
1227
+ firm = companies(:first_firm)
1228
+ client_id = firm.dependent_clients_of_firm.first.id
1229
+ assert_equal 2, firm.dependent_clients_of_firm.size
1230
+ assert_equal 1, Client.find_by_id(client_id).client_of
1231
+
1232
+ # :delete_all is called on each client since the dependent options is :destroy
1233
+ firm.dependent_clients_of_firm.clear
1234
+
1235
+ assert_equal 0, firm.dependent_clients_of_firm.size
1236
+ assert_equal 0, firm.dependent_clients_of_firm.reload.size
1237
+ assert_equal [], Client.destroyed_client_ids[firm.id]
1238
+
1239
+ # Should be destroyed since the association is dependent.
1240
+ assert_nil Client.find_by_id(client_id)
1241
+ end
1242
+
1243
+ def test_delete_all_with_option_delete_all
1244
+ firm = companies(:first_firm)
1245
+ client_id = firm.dependent_clients_of_firm.first.id
1246
+ firm.dependent_clients_of_firm.delete_all(:delete_all)
1247
+ assert_nil Client.find_by_id(client_id)
1248
+ end
1249
+
1250
+ def test_delete_all_accepts_limited_parameters
1251
+ firm = companies(:first_firm)
1252
+ assert_raise(ArgumentError) do
1253
+ firm.dependent_clients_of_firm.delete_all(:destroy)
1254
+ end
1255
+ end
1256
+
1257
+ def test_clearing_an_exclusively_dependent_association_collection
1258
+ firm = companies(:first_firm)
1259
+ client_id = firm.exclusively_dependent_clients_of_firm.first.id
1260
+ assert_equal 2, firm.exclusively_dependent_clients_of_firm.size
1261
+
1262
+ assert_equal [], Client.destroyed_client_ids[firm.id]
1263
+
1264
+ # :exclusively_dependent means each client is deleted directly from
1265
+ # the database without looping through them calling destroy.
1266
+ firm.exclusively_dependent_clients_of_firm.clear
1267
+
1268
+ assert_equal 0, firm.exclusively_dependent_clients_of_firm.size
1269
+ assert_equal 0, firm.exclusively_dependent_clients_of_firm.reload.size
1270
+ # no destroy-filters should have been called
1271
+ assert_equal [], Client.destroyed_client_ids[firm.id]
1272
+
1273
+ # Should be destroyed since the association is exclusively dependent.
1274
+ assert_nil Client.find_by_id(client_id)
1275
+ end
1276
+
1277
+ def test_dependent_association_respects_optional_conditions_on_delete
1278
+ firm = companies(:odegy)
1279
+ Client.create(:client_of => firm.id, :name => "BigShot Inc.")
1280
+ Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
1281
+ # only one of two clients is included in the association due to the :conditions key
1282
+ assert_equal 2, Client.where(client_of: firm.id).size
1283
+ assert_equal 1, firm.dependent_conditional_clients_of_firm.size
1284
+ firm.destroy
1285
+ # only the correctly associated client should have been deleted
1286
+ assert_equal 1, Client.where(client_of: firm.id).size
1287
+ end
1288
+
1289
+ def test_dependent_association_respects_optional_sanitized_conditions_on_delete
1290
+ firm = companies(:odegy)
1291
+ Client.create(:client_of => firm.id, :name => "BigShot Inc.")
1292
+ Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
1293
+ # only one of two clients is included in the association due to the :conditions key
1294
+ assert_equal 2, Client.where(client_of: firm.id).size
1295
+ assert_equal 1, firm.dependent_sanitized_conditional_clients_of_firm.size
1296
+ firm.destroy
1297
+ # only the correctly associated client should have been deleted
1298
+ assert_equal 1, Client.where(client_of: firm.id).size
1299
+ end
1300
+
1301
+ def test_dependent_association_respects_optional_hash_conditions_on_delete
1302
+ firm = companies(:odegy)
1303
+ Client.create(:client_of => firm.id, :name => "BigShot Inc.")
1304
+ Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
1305
+ # only one of two clients is included in the association due to the :conditions key
1306
+ assert_equal 2, Client.where(client_of: firm.id).size
1307
+ assert_equal 1, firm.dependent_sanitized_conditional_clients_of_firm.size
1308
+ firm.destroy
1309
+ # only the correctly associated client should have been deleted
1310
+ assert_equal 1, Client.where(client_of: firm.id).size
1311
+ end
1312
+
1313
+ def test_delete_all_association_with_primary_key_deletes_correct_records
1314
+ firm = Firm.first
1315
+ # break the vanilla firm_id foreign key
1316
+ assert_equal 3, firm.clients.count
1317
+ firm.clients.first.update_columns(firm_id: nil)
1318
+ assert_equal 2, firm.clients.reload.count
1319
+ assert_equal 2, firm.clients_using_primary_key_with_delete_all.count
1320
+ old_record = firm.clients_using_primary_key_with_delete_all.first
1321
+ firm = Firm.first
1322
+ firm.destroy
1323
+ assert_nil Client.find_by_id(old_record.id)
1324
+ end
1325
+
1326
+ def test_creation_respects_hash_condition
1327
+ ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.build
1328
+
1329
+ assert ms_client.save
1330
+ assert_equal 'Microsoft', ms_client.name
1331
+
1332
+ another_ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.create
1333
+
1334
+ assert another_ms_client.persisted?
1335
+ assert_equal 'Microsoft', another_ms_client.name
1336
+ end
1337
+
1338
+ def test_clearing_without_initial_access
1339
+ firm = companies(:first_firm)
1340
+
1341
+ firm.clients_of_firm.clear
1342
+
1343
+ assert_equal 0, firm.clients_of_firm.size
1344
+ assert_equal 0, firm.clients_of_firm.reload.size
1345
+ end
1346
+
1347
+ def test_deleting_a_item_which_is_not_in_the_collection
1348
+ force_signal37_to_load_all_clients_of_firm
1349
+ summit = Client.find_by_name('Summit')
1350
+ companies(:first_firm).clients_of_firm.delete(summit)
1351
+ assert_equal 2, companies(:first_firm).clients_of_firm.size
1352
+ assert_equal 2, companies(:first_firm).clients_of_firm.reload.size
1353
+ assert_equal 2, summit.client_of
1354
+ end
1355
+
1356
+ def test_deleting_by_integer_id
1357
+ david = Developer.find(1)
1358
+
1359
+ assert_difference 'david.projects.count', -1 do
1360
+ assert_equal 1, david.projects.delete(1).size
1361
+ end
1362
+
1363
+ assert_equal 1, david.projects.size
1364
+ end
1365
+
1366
+ def test_deleting_by_string_id
1367
+ david = Developer.find(1)
1368
+
1369
+ assert_difference 'david.projects.count', -1 do
1370
+ assert_equal 1, david.projects.delete('1').size
1371
+ end
1372
+
1373
+ assert_equal 1, david.projects.size
1374
+ end
1375
+
1376
+ def test_deleting_self_type_mismatch
1377
+ david = Developer.find(1)
1378
+ david.projects.reload
1379
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(Project.find(1).developers) }
1380
+ end
1381
+
1382
+ def test_destroying
1383
+ force_signal37_to_load_all_clients_of_firm
1384
+
1385
+ assert_difference "Client.count", -1 do
1386
+ companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first)
1387
+ end
1388
+
1389
+ assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1390
+ assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
1391
+ end
1392
+
1393
+ def test_destroying_by_integer_id
1394
+ force_signal37_to_load_all_clients_of_firm
1395
+
1396
+ assert_difference "Client.count", -1 do
1397
+ companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first.id)
1398
+ end
1399
+
1400
+ assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1401
+ assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
1402
+ end
1403
+
1404
+ def test_destroying_by_string_id
1405
+ force_signal37_to_load_all_clients_of_firm
1406
+
1407
+ assert_difference "Client.count", -1 do
1408
+ companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first.id.to_s)
1409
+ end
1410
+
1411
+ assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1412
+ assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
1413
+ end
1414
+
1415
+ def test_destroying_a_collection
1416
+ force_signal37_to_load_all_clients_of_firm
1417
+ companies(:first_firm).clients_of_firm.create("name" => "Another Client")
1418
+ assert_equal 3, companies(:first_firm).clients_of_firm.size
1419
+
1420
+ assert_difference "Client.count", -2 do
1421
+ companies(:first_firm).clients_of_firm.destroy([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1]])
1422
+ end
1423
+
1424
+ assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1425
+ assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
1426
+ end
1427
+
1428
+ def test_destroy_all
1429
+ force_signal37_to_load_all_clients_of_firm
1430
+ clients = companies(:first_firm).clients_of_firm.to_a
1431
+ assert !clients.empty?, "37signals has clients after load"
1432
+ destroyed = companies(:first_firm).clients_of_firm.destroy_all
1433
+ assert_equal clients.sort_by(&:id), destroyed.sort_by(&:id)
1434
+ assert destroyed.all?(&:frozen?), "destroyed clients should be frozen"
1435
+ assert companies(:first_firm).clients_of_firm.empty?, "37signals has no clients after destroy all"
1436
+ assert companies(:first_firm).clients_of_firm.reload.empty?, "37signals has no clients after destroy all and refresh"
1437
+ end
1438
+
1439
+ def test_dependence
1440
+ firm = companies(:first_firm)
1441
+ assert_equal 3, firm.clients.size
1442
+ firm.destroy
1443
+ assert Client.all.merge!(:where => "firm_id=#{firm.id}").to_a.empty?
1444
+ end
1445
+
1446
+ def test_dependence_for_associations_with_hash_condition
1447
+ david = authors(:david)
1448
+ assert_difference('Post.count', -1) { assert david.destroy }
1449
+ end
1450
+
1451
+ def test_destroy_dependent_when_deleted_from_association
1452
+ # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
1453
+ firm = Firm.all.merge!(:order => "id").first
1454
+ assert_equal 3, firm.clients.size
1455
+
1456
+ client = firm.clients.first
1457
+ firm.clients.delete(client)
1458
+
1459
+ assert_raise(ActiveRecord::RecordNotFound) { Client.find(client.id) }
1460
+ assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(client.id) }
1461
+ assert_equal 2, firm.clients.size
1462
+ end
1463
+
1464
+ def test_three_levels_of_dependence
1465
+ topic = Topic.create "title" => "neat and simple"
1466
+ reply = topic.replies.create "title" => "neat and simple", "content" => "still digging it"
1467
+ reply.replies.create "title" => "neat and simple", "content" => "ain't complaining"
1468
+
1469
+ assert_nothing_raised { topic.destroy }
1470
+ end
1471
+
1472
+ def test_dependence_with_transaction_support_on_failure
1473
+ firm = companies(:first_firm)
1474
+ clients = firm.clients
1475
+ assert_equal 3, clients.length
1476
+ clients.last.instance_eval { def overwrite_to_raise() raise "Trigger rollback" end }
1477
+
1478
+ firm.destroy rescue "do nothing"
1479
+
1480
+ assert_equal 3, Client.all.merge!(:where => "firm_id=#{firm.id}").to_a.size
1481
+ end
1482
+
1483
+ def test_dependence_on_account
1484
+ num_accounts = Account.count
1485
+ companies(:first_firm).destroy
1486
+ assert_equal num_accounts - 1, Account.count
1487
+ end
1488
+
1489
+ def test_depends_and_nullify
1490
+ num_accounts = Account.count
1491
+
1492
+ core = companies(:rails_core)
1493
+ assert_equal accounts(:rails_core_account), core.account
1494
+ assert_equal companies(:leetsoft, :jadedpixel), core.companies
1495
+ core.destroy
1496
+ assert_nil accounts(:rails_core_account).reload.firm_id
1497
+ assert_nil companies(:leetsoft).reload.client_of
1498
+ assert_nil companies(:jadedpixel).reload.client_of
1499
+
1500
+ assert_equal num_accounts, Account.count
1501
+ end
1502
+
1503
+ def test_restrict_with_exception
1504
+ firm = RestrictedWithExceptionFirm.create!(:name => 'restrict')
1505
+ firm.companies.create(:name => 'child')
1506
+
1507
+ assert !firm.companies.empty?
1508
+ assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy }
1509
+ assert RestrictedWithExceptionFirm.exists?(:name => 'restrict')
1510
+ assert firm.companies.exists?(:name => 'child')
1511
+ end
1512
+
1513
+ def test_restrict_with_error_is_deprecated_using_key_many
1514
+ I18n.backend = I18n::Backend::Simple.new
1515
+ I18n.backend.store_translations :en, activerecord: { errors: { messages: { restrict_dependent_destroy: { many: 'message for deprecated key' } } } }
1516
+
1517
+ firm = RestrictedWithErrorFirm.create!(name: 'restrict')
1518
+ firm.companies.create(name: 'child')
1519
+
1520
+ assert !firm.companies.empty?
1521
+
1522
+ assert_deprecated { firm.destroy }
1523
+
1524
+ assert !firm.errors.empty?
1525
+
1526
+ assert_equal 'message for deprecated key', firm.errors[:base].first
1527
+ assert RestrictedWithErrorFirm.exists?(name: 'restrict')
1528
+ assert firm.companies.exists?(name: 'child')
1529
+ ensure
1530
+ I18n.backend.reload!
1531
+ end
1532
+
1533
+ def test_restrict_with_error
1534
+ firm = RestrictedWithErrorFirm.create!(:name => 'restrict')
1535
+ firm.companies.create(:name => 'child')
1536
+
1537
+ assert !firm.companies.empty?
1538
+
1539
+ firm.destroy
1540
+
1541
+ assert !firm.errors.empty?
1542
+
1543
+ assert_equal "Cannot delete record because dependent companies exist", firm.errors[:base].first
1544
+ assert RestrictedWithErrorFirm.exists?(:name => 'restrict')
1545
+ assert firm.companies.exists?(:name => 'child')
1546
+ end
1547
+
1548
+ def test_restrict_with_error_with_locale
1549
+ I18n.backend = I18n::Backend::Simple.new
1550
+ I18n.backend.store_translations 'en', activerecord: {attributes: {restricted_with_error_firm: {companies: 'client companies'}}}
1551
+ firm = RestrictedWithErrorFirm.create!(name: 'restrict')
1552
+ firm.companies.create(name: 'child')
1553
+
1554
+ assert !firm.companies.empty?
1555
+
1556
+ firm.destroy
1557
+
1558
+ assert !firm.errors.empty?
1559
+
1560
+ assert_equal "Cannot delete record because dependent client companies exist", firm.errors[:base].first
1561
+ assert RestrictedWithErrorFirm.exists?(name: 'restrict')
1562
+ assert firm.companies.exists?(name: 'child')
1563
+ ensure
1564
+ I18n.backend.reload!
1565
+ end
1566
+
1567
+ def test_included_in_collection
1568
+ assert_equal true, companies(:first_firm).clients.include?(Client.find(2))
1569
+ end
1570
+
1571
+ def test_included_in_collection_for_new_records
1572
+ client = Client.create(:name => 'Persisted')
1573
+ assert_nil client.client_of
1574
+ assert_equal false, Firm.new.clients_of_firm.include?(client),
1575
+ 'includes a client that does not belong to any firm'
1576
+ end
1577
+
1578
+ def test_adding_array_and_collection
1579
+ assert_nothing_raised { Firm.first.clients + Firm.all.last.clients }
1580
+ end
1581
+
1582
+ def test_replace_with_less
1583
+ firm = Firm.all.merge!(:order => "id").first
1584
+ firm.clients = [companies(:first_client)]
1585
+ assert firm.save, "Could not save firm"
1586
+ firm.reload
1587
+ assert_equal 1, firm.clients.length
1588
+ end
1589
+
1590
+ def test_replace_with_less_and_dependent_nullify
1591
+ num_companies = Company.count
1592
+ companies(:rails_core).companies = []
1593
+ assert_equal num_companies, Company.count
1594
+ end
1595
+
1596
+ def test_replace_with_new
1597
+ firm = Firm.all.merge!(:order => "id").first
1598
+ firm.clients = [companies(:second_client), Client.new("name" => "New Client")]
1599
+ firm.save
1600
+ firm.reload
1601
+ assert_equal 2, firm.clients.length
1602
+ assert_equal false, firm.clients.include?(:first_client)
1603
+ end
1604
+
1605
+ def test_replace_failure
1606
+ firm = companies(:first_firm)
1607
+ account = Account.new
1608
+ orig_accounts = firm.accounts.to_a
1609
+
1610
+ assert !account.valid?
1611
+ assert !orig_accounts.empty?
1612
+ error = assert_raise ActiveRecord::RecordNotSaved do
1613
+ firm.accounts = [account]
1614
+ end
1615
+
1616
+ assert_equal orig_accounts, firm.accounts
1617
+ assert_equal "Failed to replace accounts because one or more of the " \
1618
+ "new records could not be saved.", error.message
1619
+ end
1620
+
1621
+ def test_replace_with_same_content
1622
+ firm = Firm.first
1623
+ firm.clients = []
1624
+ firm.save
1625
+
1626
+ assert_queries(0, ignore_none: true) do
1627
+ firm.clients = []
1628
+ end
1629
+
1630
+ assert_equal [], firm.send('clients=', [])
1631
+ end
1632
+
1633
+ def test_transactions_when_replacing_on_persisted
1634
+ good = Client.new(:name => "Good")
1635
+ bad = Client.new(:name => "Bad", :raise_on_save => true)
1636
+
1637
+ companies(:first_firm).clients_of_firm = [good]
1638
+
1639
+ begin
1640
+ companies(:first_firm).clients_of_firm = [bad]
1641
+ rescue Client::RaisedOnSave
1642
+ end
1643
+
1644
+ assert_equal [good], companies(:first_firm).clients_of_firm.reload
1645
+ end
1646
+
1647
+ def test_transactions_when_replacing_on_new_record
1648
+ assert_no_queries(ignore_none: false) do
1649
+ firm = Firm.new
1650
+ firm.clients_of_firm = [Client.new("name" => "New Client")]
1651
+ end
1652
+ end
1653
+
1654
+ def test_get_ids
1655
+ assert_equal [companies(:first_client).id, companies(:second_client).id, companies(:another_first_firm_client).id], companies(:first_firm).client_ids
1656
+ end
1657
+
1658
+ def test_get_ids_for_loaded_associations
1659
+ company = companies(:first_firm)
1660
+ company.clients.reload
1661
+ assert_queries(0) do
1662
+ company.client_ids
1663
+ company.client_ids
1664
+ end
1665
+ end
1666
+
1667
+ def test_get_ids_for_unloaded_associations_does_not_load_them
1668
+ company = companies(:first_firm)
1669
+ assert !company.clients.loaded?
1670
+ assert_equal [companies(:first_client).id, companies(:second_client).id, companies(:another_first_firm_client).id], company.client_ids
1671
+ assert !company.clients.loaded?
1672
+ end
1673
+
1674
+ def test_get_ids_ignores_include_option
1675
+ assert_equal [readers(:michael_welcome).id], posts(:welcome).readers_with_person_ids
1676
+ end
1677
+
1678
+ def test_get_ids_for_ordered_association
1679
+ assert_equal [companies(:another_first_firm_client).id, companies(:second_client).id, companies(:first_client).id], companies(:first_firm).clients_ordered_by_name_ids
1680
+ end
1681
+
1682
+ def test_get_ids_for_association_on_new_record_does_not_try_to_find_records
1683
+ Company.columns # Load schema information so we don't query below
1684
+ Contract.columns # if running just this test.
1685
+
1686
+ company = Company.new
1687
+ assert_queries(0) do
1688
+ company.contract_ids
1689
+ end
1690
+
1691
+ assert_equal [], company.contract_ids
1692
+ end
1693
+
1694
+ def test_set_ids_for_association_on_new_record_applies_association_correctly
1695
+ contract_a = Contract.create!
1696
+ contract_b = Contract.create!
1697
+ Contract.create! # another contract
1698
+ company = Company.new(:name => "Some Company")
1699
+
1700
+ company.contract_ids = [contract_a.id, contract_b.id]
1701
+ assert_equal [contract_a.id, contract_b.id], company.contract_ids
1702
+ assert_equal [contract_a, contract_b], company.contracts
1703
+
1704
+ company.save!
1705
+ assert_equal company, contract_a.reload.company
1706
+ assert_equal company, contract_b.reload.company
1707
+ end
1708
+
1709
+ def test_assign_ids_ignoring_blanks
1710
+ firm = Firm.create!(:name => 'Apple')
1711
+ firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, '']
1712
+ firm.save!
1713
+
1714
+ assert_equal 2, firm.clients.reload.size
1715
+ assert_equal true, firm.clients.include?(companies(:second_client))
1716
+ end
1717
+
1718
+ def test_get_ids_for_through
1719
+ assert_equal [comments(:eager_other_comment1).id], authors(:mary).comment_ids
1720
+ end
1721
+
1722
+ def test_modifying_a_through_a_has_many_should_raise
1723
+ [
1724
+ lambda { authors(:mary).comment_ids = [comments(:greetings).id, comments(:more_greetings).id] },
1725
+ lambda { authors(:mary).comments = [comments(:greetings), comments(:more_greetings)] },
1726
+ lambda { authors(:mary).comments << Comment.create!(:body => "Yay", :post_id => 424242) },
1727
+ lambda { authors(:mary).comments.delete(authors(:mary).comments.first) },
1728
+ ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
1729
+ end
1730
+
1731
+ def test_dynamic_find_should_respect_association_order_for_through
1732
+ assert_equal Comment.find(10), authors(:david).comments_desc.where("comments.type = 'SpecialComment'").first
1733
+ assert_equal Comment.find(10), authors(:david).comments_desc.find_by_type('SpecialComment')
1734
+ end
1735
+
1736
+ def test_has_many_through_respects_hash_conditions
1737
+ assert_equal authors(:david).hello_posts, authors(:david).hello_posts_with_hash_conditions
1738
+ assert_equal authors(:david).hello_post_comments, authors(:david).hello_post_comments_with_hash_conditions
1739
+ end
1740
+
1741
+ def test_include_uses_array_include_after_loaded
1742
+ firm = companies(:first_firm)
1743
+ firm.clients.load_target
1744
+
1745
+ client = firm.clients.first
1746
+
1747
+ assert_no_queries do
1748
+ assert firm.clients.loaded?
1749
+ assert_equal true, firm.clients.include?(client)
1750
+ end
1751
+ end
1752
+
1753
+ def test_include_checks_if_record_exists_if_target_not_loaded
1754
+ firm = companies(:first_firm)
1755
+ client = firm.clients.first
1756
+
1757
+ firm.reload
1758
+ assert ! firm.clients.loaded?
1759
+ assert_queries(1) do
1760
+ assert_equal true, firm.clients.include?(client)
1761
+ end
1762
+ assert ! firm.clients.loaded?
1763
+ end
1764
+
1765
+ def test_include_returns_false_for_non_matching_record_to_verify_scoping
1766
+ firm = companies(:first_firm)
1767
+ client = Client.create!(:name => 'Not Associated')
1768
+
1769
+ assert ! firm.clients.loaded?
1770
+ assert_equal false, firm.clients.include?(client)
1771
+ end
1772
+
1773
+ def test_calling_first_nth_or_last_on_association_should_not_load_association
1774
+ firm = companies(:first_firm)
1775
+ firm.clients.first
1776
+ firm.clients.second
1777
+ firm.clients.last
1778
+ assert !firm.clients.loaded?
1779
+ end
1780
+
1781
+ def test_calling_first_or_last_on_loaded_association_should_not_fetch_with_query
1782
+ firm = companies(:first_firm)
1783
+ firm.clients.load_target
1784
+ assert firm.clients.loaded?
1785
+
1786
+ assert_no_queries(ignore_none: false) do
1787
+ firm.clients.first
1788
+ assert_equal 2, firm.clients.first(2).size
1789
+ firm.clients.last
1790
+ assert_equal 2, firm.clients.last(2).size
1791
+ end
1792
+ end
1793
+
1794
+ def test_calling_first_or_last_on_existing_record_with_build_should_load_association
1795
+ firm = companies(:first_firm)
1796
+ firm.clients.build(:name => 'Foo')
1797
+ assert !firm.clients.loaded?
1798
+
1799
+ assert_queries 1 do
1800
+ firm.clients.first
1801
+ firm.clients.second
1802
+ firm.clients.last
1803
+ end
1804
+
1805
+ assert firm.clients.loaded?
1806
+ end
1807
+
1808
+ def test_calling_first_nth_or_last_on_existing_record_with_create_should_not_load_association
1809
+ firm = companies(:first_firm)
1810
+ firm.clients.create(:name => 'Foo')
1811
+ assert !firm.clients.loaded?
1812
+
1813
+ assert_queries 3 do
1814
+ firm.clients.first
1815
+ firm.clients.second
1816
+ firm.clients.last
1817
+ end
1818
+
1819
+ assert !firm.clients.loaded?
1820
+ end
1821
+
1822
+ def test_calling_first_nth_or_last_on_new_record_should_not_run_queries
1823
+ firm = Firm.new
1824
+
1825
+ assert_no_queries do
1826
+ firm.clients.first
1827
+ firm.clients.second
1828
+ firm.clients.last
1829
+ end
1830
+ end
1831
+
1832
+ def test_calling_first_or_last_with_integer_on_association_should_not_load_association
1833
+ firm = companies(:first_firm)
1834
+ firm.clients.create(:name => 'Foo')
1835
+ assert !firm.clients.loaded?
1836
+
1837
+ assert_queries 2 do
1838
+ firm.clients.first(2)
1839
+ firm.clients.last(2)
1840
+ end
1841
+
1842
+ assert !firm.clients.loaded?
1843
+ end
1844
+
1845
+ def test_calling_many_should_count_instead_of_loading_association
1846
+ firm = companies(:first_firm)
1847
+ assert_queries(1) do
1848
+ firm.clients.many? # use count query
1849
+ end
1850
+ assert !firm.clients.loaded?
1851
+ end
1852
+
1853
+ def test_calling_many_on_loaded_association_should_not_use_query
1854
+ firm = companies(:first_firm)
1855
+ firm.clients.collect # force load
1856
+ assert_no_queries { assert firm.clients.many? }
1857
+ end
1858
+
1859
+ def test_calling_many_should_defer_to_collection_if_using_a_block
1860
+ firm = companies(:first_firm)
1861
+ assert_queries(1) do
1862
+ firm.clients.expects(:size).never
1863
+ firm.clients.many? { true }
1864
+ end
1865
+ assert firm.clients.loaded?
1866
+ end
1867
+
1868
+ def test_calling_many_should_return_false_if_none_or_one
1869
+ firm = companies(:another_firm)
1870
+ assert !firm.clients_like_ms.many?
1871
+ assert_equal 0, firm.clients_like_ms.size
1872
+
1873
+ firm = companies(:first_firm)
1874
+ assert !firm.limited_clients.many?
1875
+ assert_equal 1, firm.limited_clients.size
1876
+ end
1877
+
1878
+ def test_calling_many_should_return_true_if_more_than_one
1879
+ firm = companies(:first_firm)
1880
+ assert firm.clients.many?
1881
+ assert_equal 3, firm.clients.size
1882
+ end
1883
+
1884
+ def test_calling_none_should_count_instead_of_loading_association
1885
+ firm = companies(:first_firm)
1886
+ assert_queries(1) do
1887
+ firm.clients.none? # use count query
1888
+ end
1889
+ assert !firm.clients.loaded?
1890
+ end
1891
+
1892
+ def test_calling_none_on_loaded_association_should_not_use_query
1893
+ firm = companies(:first_firm)
1894
+ firm.clients.collect # force load
1895
+ assert_no_queries { assert ! firm.clients.none? }
1896
+ end
1897
+
1898
+ def test_calling_none_should_defer_to_collection_if_using_a_block
1899
+ firm = companies(:first_firm)
1900
+ assert_queries(1) do
1901
+ firm.clients.expects(:size).never
1902
+ firm.clients.none? { true }
1903
+ end
1904
+ assert firm.clients.loaded?
1905
+ end
1906
+
1907
+ def test_calling_none_should_return_true_if_none
1908
+ firm = companies(:another_firm)
1909
+ assert firm.clients_like_ms.none?
1910
+ assert_equal 0, firm.clients_like_ms.size
1911
+ end
1912
+
1913
+ def test_calling_none_should_return_false_if_any
1914
+ firm = companies(:first_firm)
1915
+ assert !firm.limited_clients.none?
1916
+ assert_equal 1, firm.limited_clients.size
1917
+ end
1918
+
1919
+ def test_calling_one_should_count_instead_of_loading_association
1920
+ firm = companies(:first_firm)
1921
+ assert_queries(1) do
1922
+ firm.clients.one? # use count query
1923
+ end
1924
+ assert !firm.clients.loaded?
1925
+ end
1926
+
1927
+ def test_calling_one_on_loaded_association_should_not_use_query
1928
+ firm = companies(:first_firm)
1929
+ firm.clients.collect # force load
1930
+ assert_no_queries { assert ! firm.clients.one? }
1931
+ end
1932
+
1933
+ def test_calling_one_should_defer_to_collection_if_using_a_block
1934
+ firm = companies(:first_firm)
1935
+ assert_queries(1) do
1936
+ firm.clients.expects(:size).never
1937
+ firm.clients.one? { true }
1938
+ end
1939
+ assert firm.clients.loaded?
1940
+ end
1941
+
1942
+ def test_calling_one_should_return_false_if_zero
1943
+ firm = companies(:another_firm)
1944
+ assert ! firm.clients_like_ms.one?
1945
+ assert_equal 0, firm.clients_like_ms.size
1946
+ end
1947
+
1948
+ def test_calling_one_should_return_true_if_one
1949
+ firm = companies(:first_firm)
1950
+ assert firm.limited_clients.one?
1951
+ assert_equal 1, firm.limited_clients.size
1952
+ end
1953
+
1954
+ def test_calling_one_should_return_false_if_more_than_one
1955
+ firm = companies(:first_firm)
1956
+ assert ! firm.clients.one?
1957
+ assert_equal 3, firm.clients.size
1958
+ end
1959
+
1960
+ def test_joins_with_namespaced_model_should_use_correct_type
1961
+ old = ActiveRecord::Base.store_full_sti_class
1962
+ ActiveRecord::Base.store_full_sti_class = true
1963
+
1964
+ firm = Namespaced::Firm.create({ :name => 'Some Company' })
1965
+ firm.clients.create({ :name => 'Some Client' })
1966
+
1967
+ stats = Namespaced::Firm.all.merge!(
1968
+ :select => "#{Namespaced::Firm.table_name}.id, COUNT(#{Namespaced::Client.table_name}.id) AS num_clients",
1969
+ :joins => :clients,
1970
+ :group => "#{Namespaced::Firm.table_name}.id"
1971
+ ).find firm.id
1972
+ assert_equal 1, stats.num_clients.to_i
1973
+ ensure
1974
+ ActiveRecord::Base.store_full_sti_class = old
1975
+ end
1976
+
1977
+ def test_association_proxy_transaction_method_starts_transaction_in_association_class
1978
+ Comment.expects(:transaction)
1979
+ Post.first.comments.transaction do
1980
+ # nothing
1981
+ end
1982
+ end
1983
+
1984
+ def test_sending_new_to_association_proxy_should_have_same_effect_as_calling_new
1985
+ client_association = companies(:first_firm).clients
1986
+ assert_equal client_association.new.attributes, client_association.send(:new).attributes
1987
+ end
1988
+
1989
+ def test_respond_to_private_class_methods
1990
+ client_association = companies(:first_firm).clients
1991
+ assert !client_association.respond_to?(:private_method)
1992
+ assert client_association.respond_to?(:private_method, true)
1993
+ end
1994
+
1995
+ def test_creating_using_primary_key
1996
+ firm = Firm.all.merge!(:order => "id").first
1997
+ client = firm.clients_using_primary_key.create!(:name => 'test')
1998
+ assert_equal firm.name, client.firm_name
1999
+ end
2000
+
2001
+ def test_defining_has_many_association_with_delete_all_dependency_lazily_evaluates_target_class
2002
+ ActiveRecord::Reflection::AssociationReflection.any_instance.expects(:class_name).never
2003
+ class_eval(<<-EOF, __FILE__, __LINE__ + 1)
2004
+ class DeleteAllModel < ActiveRecord::Base
2005
+ has_many :nonentities, :dependent => :delete_all
2006
+ end
2007
+ EOF
2008
+ end
2009
+
2010
+ def test_defining_has_many_association_with_nullify_dependency_lazily_evaluates_target_class
2011
+ ActiveRecord::Reflection::AssociationReflection.any_instance.expects(:class_name).never
2012
+ class_eval(<<-EOF, __FILE__, __LINE__ + 1)
2013
+ class NullifyModel < ActiveRecord::Base
2014
+ has_many :nonentities, :dependent => :nullify
2015
+ end
2016
+ EOF
2017
+ end
2018
+
2019
+ def test_attributes_are_being_set_when_initialized_from_has_many_association_with_where_clause
2020
+ new_comment = posts(:welcome).comments.where(:body => "Some content").build
2021
+ assert_equal new_comment.body, "Some content"
2022
+ end
2023
+
2024
+ def test_attributes_are_being_set_when_initialized_from_has_many_association_with_multiple_where_clauses
2025
+ new_comment = posts(:welcome).comments.where(:body => "Some content").where(:type => 'SpecialComment').build
2026
+ assert_equal new_comment.body, "Some content"
2027
+ assert_equal new_comment.type, "SpecialComment"
2028
+ assert_equal new_comment.post_id, posts(:welcome).id
2029
+ end
2030
+
2031
+ def test_include_method_in_has_many_association_should_return_true_for_instance_added_with_build
2032
+ post = Post.new
2033
+ comment = post.comments.build
2034
+ assert_equal true, post.comments.include?(comment)
2035
+ end
2036
+
2037
+ def test_load_target_respects_protected_attributes
2038
+ topic = Topic.create!
2039
+ reply = topic.replies.create(:title => "reply 1")
2040
+ reply.approved = false
2041
+ reply.save!
2042
+
2043
+ # Save with a different object instance, so the instance that's still held
2044
+ # in topic.relies doesn't know about the changed attribute.
2045
+ reply2 = Reply.find(reply.id)
2046
+ reply2.approved = true
2047
+ reply2.save!
2048
+
2049
+ # Force loading the collection from the db. This will merge the existing
2050
+ # object (reply) with what gets loaded from the db (which includes the
2051
+ # changed approved attribute). approved is a protected attribute, so if mass
2052
+ # assignment is used, it won't get updated and will still be false.
2053
+ first = topic.replies.to_a.first
2054
+ assert_equal reply.id, first.id
2055
+ assert_equal true, first.approved?
2056
+ end
2057
+
2058
+ def test_to_a_should_dup_target
2059
+ ary = topics(:first).replies.to_a
2060
+ target = topics(:first).replies.target
2061
+
2062
+ assert_not_equal target.object_id, ary.object_id
2063
+ end
2064
+
2065
+ def test_merging_with_custom_attribute_writer
2066
+ bulb = Bulb.new(:color => "red")
2067
+ assert_equal "RED!", bulb.color
2068
+
2069
+ car = Car.create!
2070
+ car.bulbs << bulb
2071
+
2072
+ assert_equal "RED!", car.bulbs.to_a.first.color
2073
+ end
2074
+
2075
+ def test_abstract_class_with_polymorphic_has_many
2076
+ post = SubStiPost.create! :title => "fooo", :body => "baa"
2077
+ tagging = Tagging.create! :taggable => post
2078
+ assert_equal [tagging], post.taggings
2079
+ end
2080
+
2081
+ def test_with_polymorphic_has_many_with_custom_columns_name
2082
+ post = Post.create! :title => 'foo', :body => 'bar'
2083
+ image = Image.create!
2084
+
2085
+ post.images << image
2086
+
2087
+ assert_equal [image], post.images
2088
+ end
2089
+
2090
+ def test_build_with_polymorphic_has_many_does_not_allow_to_override_type_and_id
2091
+ welcome = posts(:welcome)
2092
+ tagging = welcome.taggings.build(:taggable_id => 99, :taggable_type => 'ShouldNotChange')
2093
+
2094
+ assert_equal welcome.id, tagging.taggable_id
2095
+ assert_equal 'Post', tagging.taggable_type
2096
+ end
2097
+
2098
+ def test_dont_call_save_callbacks_twice_on_has_many
2099
+ firm = companies(:first_firm)
2100
+ contract = firm.contracts.create!
2101
+
2102
+ assert_equal 1, contract.hi_count
2103
+ assert_equal 1, contract.bye_count
2104
+ end
2105
+
2106
+ def test_association_attributes_are_available_to_after_initialize
2107
+ car = Car.create(:name => 'honda')
2108
+ bulb = car.bulbs.build
2109
+
2110
+ assert_equal car.id, bulb.attributes_after_initialize['car_id']
2111
+ end
2112
+
2113
+ def test_attributes_are_set_when_initialized_from_has_many_null_relationship
2114
+ car = Car.new name: 'honda'
2115
+ bulb = car.bulbs.where(name: 'headlight').first_or_initialize
2116
+ assert_equal 'headlight', bulb.name
2117
+ end
2118
+
2119
+ def test_attributes_are_set_when_initialized_from_polymorphic_has_many_null_relationship
2120
+ post = Post.new title: 'title', body: 'bar'
2121
+ tag = Tag.create!(name: 'foo')
2122
+
2123
+ tagging = post.taggings.where(tag: tag).first_or_initialize
2124
+
2125
+ assert_equal tag.id, tagging.tag_id
2126
+ assert_equal 'Post', tagging.taggable_type
2127
+ end
2128
+
2129
+ def test_replace
2130
+ car = Car.create(:name => 'honda')
2131
+ bulb1 = car.bulbs.create
2132
+ bulb2 = Bulb.create
2133
+
2134
+ assert_equal [bulb1], car.bulbs
2135
+ car.bulbs.replace([bulb2])
2136
+ assert_equal [bulb2], car.bulbs
2137
+ assert_equal [bulb2], car.reload.bulbs
2138
+ end
2139
+
2140
+ def test_replace_returns_target
2141
+ car = Car.create(:name => 'honda')
2142
+ bulb1 = car.bulbs.create
2143
+ bulb2 = car.bulbs.create
2144
+ bulb3 = Bulb.create
2145
+
2146
+ assert_equal [bulb1, bulb2], car.bulbs
2147
+ result = car.bulbs.replace([bulb3, bulb1])
2148
+ assert_equal [bulb1, bulb3], car.bulbs
2149
+ assert_equal [bulb1, bulb3], result
2150
+ end
2151
+
2152
+ def test_collection_association_with_private_kernel_method
2153
+ firm = companies(:first_firm)
2154
+ assert_equal [accounts(:signals37)], firm.accounts.open
2155
+ end
2156
+
2157
+ test "first_or_initialize adds the record to the association" do
2158
+ firm = Firm.create! name: 'omg'
2159
+ client = firm.clients_of_firm.first_or_initialize
2160
+ assert_equal [client], firm.clients_of_firm
2161
+ end
2162
+
2163
+ test "first_or_create adds the record to the association" do
2164
+ firm = Firm.create! name: 'omg'
2165
+ firm.clients_of_firm.load_target
2166
+ client = firm.clients_of_firm.first_or_create name: 'lol'
2167
+ assert_equal [client], firm.clients_of_firm
2168
+ assert_equal [client], firm.reload.clients_of_firm
2169
+ end
2170
+
2171
+ test "delete_all, when not loaded, doesn't load the records" do
2172
+ post = posts(:welcome)
2173
+
2174
+ assert post.taggings_with_delete_all.count > 0
2175
+ assert !post.taggings_with_delete_all.loaded?
2176
+
2177
+ # 2 queries: one DELETE and another to update the counter cache
2178
+ assert_queries(2) do
2179
+ post.taggings_with_delete_all.delete_all
2180
+ end
2181
+ end
2182
+
2183
+ test "has many associations on new records use null relations" do
2184
+ post = Post.new
2185
+
2186
+ assert_no_queries(ignore_none: false) do
2187
+ assert_equal [], post.comments
2188
+ assert_equal [], post.comments.where(body: 'omg')
2189
+ assert_equal [], post.comments.pluck(:body)
2190
+ assert_equal 0, post.comments.sum(:id)
2191
+ assert_equal 0, post.comments.count
2192
+ end
2193
+ end
2194
+
2195
+ test "collection proxy respects default scope" do
2196
+ author = authors(:mary)
2197
+ assert !author.first_posts.exists?
2198
+ end
2199
+
2200
+ test "association with extend option" do
2201
+ post = posts(:welcome)
2202
+ assert_equal "lifo", post.comments_with_extend.author
2203
+ assert_equal "hello", post.comments_with_extend.greeting
2204
+ end
2205
+
2206
+ test "association with extend option with multiple extensions" do
2207
+ post = posts(:welcome)
2208
+ assert_equal "lifo", post.comments_with_extend_2.author
2209
+ assert_equal "hullo", post.comments_with_extend_2.greeting
2210
+ end
2211
+
2212
+ test "extend option affects per association" do
2213
+ post = posts(:welcome)
2214
+ assert_equal "lifo", post.comments_with_extend.author
2215
+ assert_equal "lifo", post.comments_with_extend_2.author
2216
+ assert_equal "hello", post.comments_with_extend.greeting
2217
+ assert_equal "hullo", post.comments_with_extend_2.greeting
2218
+ end
2219
+
2220
+ test "delete record with complex joins" do
2221
+ david = authors(:david)
2222
+
2223
+ post = david.posts.first
2224
+ post.type = 'PostWithSpecialCategorization'
2225
+ post.save
2226
+
2227
+ categorization = post.categorizations.first
2228
+ categorization.special = true
2229
+ categorization.save
2230
+
2231
+ assert_not_equal [], david.posts_with_special_categorizations
2232
+ david.posts_with_special_categorizations = []
2233
+ assert_equal [], david.posts_with_special_categorizations
2234
+ end
2235
+
2236
+ test "does not duplicate associations when used with natural primary keys" do
2237
+ speedometer = Speedometer.create!(id: '4')
2238
+ speedometer.minivans.create!(minivan_id: 'a-van-red' ,name: 'a van', color: 'red')
2239
+
2240
+ assert_equal 1, speedometer.minivans.to_a.size, "Only one association should be present:\n#{speedometer.minivans.to_a}"
2241
+ assert_equal 1, speedometer.reload.minivans.to_a.size
2242
+ end
2243
+
2244
+ test "can unscope the default scope of the associated model" do
2245
+ car = Car.create!
2246
+ bulb1 = Bulb.create! name: "defaulty", car: car
2247
+ bulb2 = Bulb.create! name: "other", car: car
2248
+
2249
+ assert_equal [bulb1], car.bulbs
2250
+ assert_equal [bulb1, bulb2], car.all_bulbs.sort_by(&:id)
2251
+ end
2252
+
2253
+ test "can unscope and where the default scope of the associated model" do
2254
+ Car.has_many :other_bulbs, -> { unscope(where: [:name]).where(name: 'other') }, class_name: "Bulb"
2255
+ car = Car.create!
2256
+ bulb1 = Bulb.create! name: "defaulty", car: car
2257
+ bulb2 = Bulb.create! name: "other", car: car
2258
+
2259
+ assert_equal [bulb1], car.bulbs
2260
+ assert_equal [bulb2], car.other_bulbs
2261
+ end
2262
+
2263
+ test "can rewhere the default scope of the associated model" do
2264
+ Car.has_many :old_bulbs, -> { rewhere(name: 'old') }, class_name: "Bulb"
2265
+ car = Car.create!
2266
+ bulb1 = Bulb.create! name: "defaulty", car: car
2267
+ bulb2 = Bulb.create! name: "old", car: car
2268
+
2269
+ assert_equal [bulb1], car.bulbs
2270
+ assert_equal [bulb2], car.old_bulbs
2271
+ end
2272
+
2273
+ test 'unscopes the default scope of associated model when used with include' do
2274
+ car = Car.create!
2275
+ bulb = Bulb.create! name: "other", car: car
2276
+
2277
+ assert_equal [bulb], Car.find(car.id).all_bulbs
2278
+ assert_equal [bulb], Car.includes(:all_bulbs).find(car.id).all_bulbs
2279
+ assert_equal [bulb], Car.eager_load(:all_bulbs).find(car.id).all_bulbs
2280
+ end
2281
+
2282
+ test "raises RecordNotDestroyed when replaced child can't be destroyed" do
2283
+ car = Car.create!
2284
+ original_child = FailedBulb.create!(car: car)
2285
+
2286
+ error = assert_raise(ActiveRecord::RecordNotDestroyed) do
2287
+ car.failed_bulbs = [FailedBulb.create!]
2288
+ end
2289
+
2290
+ assert_equal [original_child], car.reload.failed_bulbs
2291
+ assert_equal "Failed to destroy the record", error.message
2292
+ end
2293
+
2294
+ test 'updates counter cache when default scope is given' do
2295
+ topic = DefaultRejectedTopic.create approved: true
2296
+
2297
+ assert_difference "topic.reload.replies_count", 1 do
2298
+ topic.approved_replies.create!
2299
+ end
2300
+ end
2301
+
2302
+ test 'dangerous association name raises ArgumentError' do
2303
+ [:errors, 'errors', :save, 'save'].each do |name|
2304
+ assert_raises(ArgumentError, "Association #{name} should not be allowed") do
2305
+ Class.new(ActiveRecord::Base) do
2306
+ has_many name
2307
+ end
2308
+ end
2309
+ end
2310
+ end
2311
+
2312
+ test 'passes custom context validation to validate children' do
2313
+ pirate = FamousPirate.new
2314
+ pirate.famous_ships << ship = FamousShip.new
2315
+
2316
+ assert pirate.valid?
2317
+ assert_not pirate.valid?(:conference)
2318
+ assert_equal "can't be blank", ship.errors[:name].first
2319
+ end
2320
+
2321
+ test 'association with instance dependent scope' do
2322
+ bob = authors(:bob)
2323
+ Post.create!(title: "signed post by bob", body: "stuff", author: authors(:bob))
2324
+ Post.create!(title: "anonymous post", body: "more stuff", author: authors(:bob))
2325
+ assert_equal ["misc post by bob", "other post by bob",
2326
+ "signed post by bob"], bob.posts_with_signature.map(&:title).sort
2327
+
2328
+ assert_equal [], authors(:david).posts_with_signature.map(&:title)
2329
+ end
2330
+
2331
+ test 'associations autosaves when object is already persisted' do
2332
+ bulb = Bulb.create!
2333
+ tyre = Tyre.create!
2334
+
2335
+ car = Car.create! do |c|
2336
+ c.bulbs << bulb
2337
+ c.tyres << tyre
2338
+ end
2339
+
2340
+ assert_equal 1, car.bulbs.count
2341
+ assert_equal 1, car.tyres.count
2342
+ end
2343
+
2344
+ test 'associations replace in memory when records have the same id' do
2345
+ bulb = Bulb.create!
2346
+ car = Car.create!(bulbs: [bulb])
2347
+
2348
+ new_bulb = Bulb.find(bulb.id)
2349
+ new_bulb.name = "foo"
2350
+ car.bulbs = [new_bulb]
2351
+
2352
+ assert_equal "foo", car.bulbs.first.name
2353
+ end
2354
+
2355
+ test 'in memory replacement executes no queries' do
2356
+ bulb = Bulb.create!
2357
+ car = Car.create!(bulbs: [bulb])
2358
+
2359
+ new_bulb = Bulb.find(bulb.id)
2360
+
2361
+ assert_no_queries do
2362
+ car.bulbs = [new_bulb]
2363
+ end
2364
+ end
2365
+
2366
+ test 'in memory replacements do not execute callbacks' do
2367
+ raise_after_add = false
2368
+ klass = Class.new(ActiveRecord::Base) do
2369
+ self.table_name = :cars
2370
+ has_many :bulbs, after_add: proc { raise if raise_after_add }
2371
+
2372
+ def self.name
2373
+ "Car"
2374
+ end
2375
+ end
2376
+ bulb = Bulb.create!
2377
+ car = klass.create!(bulbs: [bulb])
2378
+
2379
+ new_bulb = Bulb.find(bulb.id)
2380
+ raise_after_add = true
2381
+
2382
+ assert_nothing_raised do
2383
+ car.bulbs = [new_bulb]
2384
+ end
2385
+ end
2386
+
2387
+ test 'in memory replacements sets inverse instance' do
2388
+ bulb = Bulb.create!
2389
+ car = Car.create!(bulbs: [bulb])
2390
+
2391
+ new_bulb = Bulb.find(bulb.id)
2392
+ car.bulbs = [new_bulb]
2393
+
2394
+ assert_same car, new_bulb.car
2395
+ end
2396
+
2397
+ test 'in memory replacement maintains order' do
2398
+ first_bulb = Bulb.create!
2399
+ second_bulb = Bulb.create!
2400
+ car = Car.create!(bulbs: [first_bulb, second_bulb])
2401
+
2402
+ same_bulb = Bulb.find(first_bulb.id)
2403
+ car.bulbs = [second_bulb, same_bulb]
2404
+
2405
+ assert_equal [first_bulb, second_bulb], car.bulbs
2406
+ end
2407
+
2408
+ test "prevent double insertion of new object when the parent association loaded in the after save callback" do
2409
+ reset_callbacks(:save, Bulb) do
2410
+ Bulb.after_save { |record| record.car.bulbs.load }
2411
+
2412
+ car = Car.create!
2413
+ car.bulbs << Bulb.new
2414
+
2415
+ assert_equal 1, car.bulbs.size
2416
+ end
2417
+ end
2418
+
2419
+ test "prevent double firing the before save callback of new object when the parent association saved in the callback" do
2420
+ reset_callbacks(:save, Bulb) do
2421
+ count = 0
2422
+ Bulb.before_save { |record| record.car.save && count += 1 }
2423
+
2424
+ car = Car.create!
2425
+ car.bulbs.create!
2426
+
2427
+ assert_equal 1, count
2428
+ end
2429
+ end
2430
+
2431
+ def test_association_force_reload_with_only_true_is_deprecated
2432
+ company = Company.find(1)
2433
+
2434
+ assert_deprecated { company.clients_of_firm(true) }
2435
+ end
2436
+
2437
+ class AuthorWithErrorDestroyingAssociation < ActiveRecord::Base
2438
+ self.table_name = "authors"
2439
+ has_many :posts_with_error_destroying,
2440
+ class_name: "PostWithErrorDestroying",
2441
+ foreign_key: :author_id,
2442
+ dependent: :destroy
2443
+ end
2444
+
2445
+ class PostWithErrorDestroying < ActiveRecord::Base
2446
+ self.table_name = "posts"
2447
+ self.inheritance_column = nil
2448
+ before_destroy -> { throw :abort }
2449
+ end
2450
+
2451
+ def test_destroy_does_not_raise_when_association_errors_on_destroy
2452
+ assert_no_difference "AuthorWithErrorDestroyingAssociation.count" do
2453
+ author = AuthorWithErrorDestroyingAssociation.first
2454
+
2455
+ assert_not author.destroy
2456
+ end
2457
+ end
2458
+
2459
+ def test_destroy_with_bang_bubbles_errors_from_associations
2460
+ error = assert_raises ActiveRecord::RecordNotDestroyed do
2461
+ AuthorWithErrorDestroyingAssociation.first.destroy!
2462
+ end
2463
+
2464
+ assert_instance_of PostWithErrorDestroying, error.record
2465
+ end
2466
+
2467
+ def test_ids_reader_memoization
2468
+ car = Car.create!(name: 'Tofaş')
2469
+ bulb = Bulb.create!(car: car)
2470
+
2471
+ assert_equal [bulb.id], car.bulb_ids
2472
+ assert_no_queries { car.bulb_ids }
2473
+ end
2474
+
2475
+ def test_loading_association_in_validate_callback_doesnt_affect_persistence
2476
+ reset_callbacks(:validation, Bulb) do
2477
+ Bulb.after_validation { |record| record.car.bulbs.load }
2478
+
2479
+ car = Car.create!(name: "Car")
2480
+ bulb = car.bulbs.create!
2481
+
2482
+ assert_equal [bulb], car.bulbs
2483
+ end
2484
+ end
2485
+
2486
+ private
2487
+
2488
+ def reset_callbacks(kind, klass)
2489
+ old_callbacks = {}
2490
+ old_callbacks[klass] = klass.send("_#{kind}_callbacks").dup
2491
+ klass.subclasses.each do |subclass|
2492
+ old_callbacks[subclass] = subclass.send("_#{kind}_callbacks").dup
2493
+ end
2494
+ yield
2495
+ ensure
2496
+ klass.send("_#{kind}_callbacks=", old_callbacks[klass])
2497
+ klass.subclasses.each do |subclass|
2498
+ subclass.send("_#{kind}_callbacks=", old_callbacks[subclass])
2499
+ end
2500
+ end
2501
+ end