ibm_db 5.6.1-arm64-darwin-24

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