ibm_db 5.2.0-x86-mingw32 → 5.3.2-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (621) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +9 -0
  3. data/LICENSE +55 -18
  4. data/ext/Makefile +15 -13
  5. data/ext/ibm_db.c +62 -57
  6. data/ext/ibm_db.o +0 -0
  7. data/ext/ibm_db.so +0 -0
  8. data/ext/mkmf.log +26 -24
  9. data/ext/ruby_ibm_db_cli.c +1 -0
  10. data/ext/ruby_ibm_db_cli.o +0 -0
  11. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +1463 -1279
  12. data/lib/ibm_db.so +1 -0
  13. data/lib/mswin32/rb3x/i386/ruby30/ibm_db.so +0 -0
  14. data/test/active_record/connection_adapters/fake_adapter.rb +5 -2
  15. data/test/activejob/destroy_association_async_test.rb +305 -0
  16. data/test/activejob/destroy_async_job_not_present_test.rb +31 -0
  17. data/test/activejob/helper.rb +15 -0
  18. data/test/assets/schema_dump_5_1.yml +345 -0
  19. data/test/cases/adapter_prevent_writes_test.rb +334 -0
  20. data/test/cases/adapter_test.rb +432 -218
  21. data/test/cases/adapters/mysql2/active_schema_test.rb +85 -75
  22. data/test/cases/adapters/mysql2/auto_increment_test.rb +34 -0
  23. data/test/cases/adapters/mysql2/bind_parameter_test.rb +5 -3
  24. data/test/cases/adapters/mysql2/boolean_test.rb +6 -4
  25. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +26 -24
  26. data/test/cases/adapters/mysql2/charset_collation_test.rb +20 -17
  27. data/test/cases/adapters/mysql2/connection_test.rb +48 -50
  28. data/test/cases/adapters/mysql2/count_deleted_rows_with_lock_test.rb +28 -0
  29. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +23 -19
  30. data/test/cases/adapters/mysql2/enum_test.rb +32 -11
  31. data/test/cases/adapters/mysql2/explain_test.rb +13 -11
  32. data/test/cases/adapters/mysql2/json_test.rb +17 -188
  33. data/test/cases/adapters/mysql2/mysql2_adapter_prevent_writes_test.rb +208 -0
  34. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +183 -28
  35. data/test/cases/adapters/mysql2/nested_deadlock_test.rb +75 -0
  36. data/test/cases/adapters/mysql2/optimizer_hints_test.rb +69 -0
  37. data/test/cases/adapters/mysql2/schema_migrations_test.rb +26 -21
  38. data/test/cases/adapters/mysql2/schema_test.rb +24 -22
  39. data/test/cases/adapters/mysql2/set_test.rb +32 -0
  40. data/test/cases/adapters/mysql2/sp_test.rb +10 -8
  41. data/test/cases/adapters/mysql2/sql_types_test.rb +8 -6
  42. data/test/cases/adapters/mysql2/table_options_test.rb +93 -10
  43. data/test/cases/adapters/mysql2/transaction_test.rb +151 -0
  44. data/test/cases/adapters/mysql2/unsigned_type_test.rb +11 -9
  45. data/test/cases/adapters/mysql2/virtual_column_test.rb +66 -0
  46. data/test/cases/adapters/postgresql/active_schema_test.rb +40 -25
  47. data/test/cases/adapters/postgresql/array_test.rb +118 -63
  48. data/test/cases/adapters/postgresql/bit_string_test.rb +12 -10
  49. data/test/cases/adapters/postgresql/bytea_test.rb +26 -25
  50. data/test/cases/adapters/postgresql/case_insensitive_test.rb +10 -9
  51. data/test/cases/adapters/postgresql/change_schema_test.rb +7 -5
  52. data/test/cases/adapters/postgresql/cidr_test.rb +2 -0
  53. data/test/cases/adapters/postgresql/citext_test.rb +58 -58
  54. data/test/cases/adapters/postgresql/collation_test.rb +17 -15
  55. data/test/cases/adapters/postgresql/composite_test.rb +25 -23
  56. data/test/cases/adapters/postgresql/connection_test.rb +73 -85
  57. data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +74 -0
  58. data/test/cases/adapters/postgresql/datatype_test.rb +19 -22
  59. data/test/cases/adapters/postgresql/date_test.rb +42 -0
  60. data/test/cases/adapters/postgresql/domain_test.rb +9 -7
  61. data/test/cases/adapters/postgresql/enum_test.rb +12 -10
  62. data/test/cases/adapters/postgresql/explain_test.rb +10 -8
  63. data/test/cases/adapters/postgresql/extension_migration_test.rb +13 -12
  64. data/test/cases/adapters/postgresql/foreign_table_test.rb +109 -0
  65. data/test/cases/adapters/postgresql/full_text_test.rb +8 -6
  66. data/test/cases/adapters/postgresql/geometric_test.rb +57 -63
  67. data/test/cases/adapters/postgresql/hstore_test.rb +288 -280
  68. data/test/cases/adapters/postgresql/infinity_test.rb +54 -15
  69. data/test/cases/adapters/postgresql/integer_test.rb +2 -0
  70. data/test/cases/adapters/postgresql/interval_test.rb +99 -0
  71. data/test/cases/adapters/postgresql/json_test.rb +16 -201
  72. data/test/cases/adapters/postgresql/ltree_test.rb +14 -16
  73. data/test/cases/adapters/postgresql/money_test.rb +47 -16
  74. data/test/cases/adapters/postgresql/network_test.rb +36 -28
  75. data/test/cases/adapters/postgresql/numbers_test.rb +7 -5
  76. data/test/cases/adapters/postgresql/optimizer_hints_test.rb +71 -0
  77. data/test/cases/adapters/postgresql/partitions_test.rb +22 -0
  78. data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +205 -0
  79. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +178 -136
  80. data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +27 -0
  81. data/test/cases/adapters/postgresql/quoting_test.rb +12 -6
  82. data/test/cases/adapters/postgresql/range_test.rb +406 -292
  83. data/test/cases/adapters/postgresql/referential_integrity_test.rb +16 -15
  84. data/test/cases/adapters/postgresql/rename_table_test.rb +9 -8
  85. data/test/cases/adapters/postgresql/schema_authorization_test.rb +14 -23
  86. data/test/cases/adapters/postgresql/schema_test.rb +207 -91
  87. data/test/cases/adapters/postgresql/serial_test.rb +9 -7
  88. data/test/cases/adapters/postgresql/statement_pool_test.rb +26 -6
  89. data/test/cases/adapters/postgresql/timestamp_test.rb +17 -15
  90. data/test/cases/adapters/postgresql/transaction_nested_test.rb +114 -0
  91. data/test/cases/adapters/postgresql/transaction_test.rb +189 -0
  92. data/test/cases/adapters/postgresql/type_lookup_test.rb +12 -10
  93. data/test/cases/adapters/postgresql/utils_test.rb +11 -9
  94. data/test/cases/adapters/postgresql/uuid_test.rb +226 -109
  95. data/test/cases/adapters/postgresql/xml_test.rb +10 -14
  96. data/test/cases/adapters/sqlite3/collation_test.rb +26 -15
  97. data/test/cases/adapters/sqlite3/copy_table_test.rb +31 -28
  98. data/test/cases/adapters/sqlite3/explain_test.rb +13 -11
  99. data/test/cases/adapters/sqlite3/json_test.rb +29 -0
  100. data/test/cases/adapters/sqlite3/quoting_test.rb +35 -57
  101. data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +186 -0
  102. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +318 -131
  103. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +11 -11
  104. data/test/cases/adapters/sqlite3/statement_pool_test.rb +7 -6
  105. data/test/cases/adapters/sqlite3/transaction_test.rb +123 -0
  106. data/test/cases/aggregations_test.rb +14 -12
  107. data/test/cases/annotate_test.rb +46 -0
  108. data/test/cases/ar_schema_test.rb +153 -86
  109. data/test/cases/arel/attributes/attribute_test.rb +1145 -0
  110. data/test/cases/arel/attributes/math_test.rb +83 -0
  111. data/test/cases/arel/attributes_test.rb +27 -0
  112. data/test/cases/arel/collectors/bind_test.rb +40 -0
  113. data/test/cases/arel/collectors/composite_test.rb +47 -0
  114. data/test/cases/arel/collectors/sql_string_test.rb +41 -0
  115. data/test/cases/arel/collectors/substitute_bind_collector_test.rb +48 -0
  116. data/test/cases/arel/crud_test.rb +65 -0
  117. data/test/cases/arel/delete_manager_test.rb +53 -0
  118. data/test/cases/arel/factory_methods_test.rb +46 -0
  119. data/test/cases/arel/helper.rb +45 -0
  120. data/test/cases/arel/insert_manager_test.rb +241 -0
  121. data/test/cases/arel/nodes/and_test.rb +30 -0
  122. data/test/cases/arel/nodes/as_test.rb +36 -0
  123. data/test/cases/arel/nodes/ascending_test.rb +46 -0
  124. data/test/cases/arel/nodes/bin_test.rb +35 -0
  125. data/test/cases/arel/nodes/binary_test.rb +29 -0
  126. data/test/cases/arel/nodes/bind_param_test.rb +22 -0
  127. data/test/cases/arel/nodes/case_test.rb +96 -0
  128. data/test/cases/arel/nodes/casted_test.rb +18 -0
  129. data/test/cases/arel/nodes/comment_test.rb +22 -0
  130. data/test/cases/arel/nodes/count_test.rb +35 -0
  131. data/test/cases/arel/nodes/delete_statement_test.rb +36 -0
  132. data/test/cases/arel/nodes/descending_test.rb +46 -0
  133. data/test/cases/arel/nodes/distinct_test.rb +21 -0
  134. data/test/cases/arel/nodes/equality_test.rb +62 -0
  135. data/test/cases/arel/nodes/extract_test.rb +43 -0
  136. data/test/cases/arel/nodes/false_test.rb +21 -0
  137. data/test/cases/arel/nodes/grouping_test.rb +26 -0
  138. data/test/cases/arel/nodes/infix_operation_test.rb +42 -0
  139. data/test/cases/arel/nodes/insert_statement_test.rb +44 -0
  140. data/test/cases/arel/nodes/named_function_test.rb +48 -0
  141. data/test/cases/arel/nodes/node_test.rb +22 -0
  142. data/test/cases/arel/nodes/not_test.rb +31 -0
  143. data/test/cases/arel/nodes/or_test.rb +36 -0
  144. data/test/cases/arel/nodes/over_test.rb +69 -0
  145. data/test/cases/arel/nodes/select_core_test.rb +79 -0
  146. data/test/cases/arel/nodes/select_statement_test.rb +51 -0
  147. data/test/cases/arel/nodes/sql_literal_test.rb +75 -0
  148. data/test/cases/arel/nodes/sum_test.rb +35 -0
  149. data/test/cases/arel/nodes/table_alias_test.rb +29 -0
  150. data/test/cases/arel/nodes/true_test.rb +21 -0
  151. data/test/cases/arel/nodes/unary_operation_test.rb +41 -0
  152. data/test/cases/arel/nodes/update_statement_test.rb +60 -0
  153. data/test/cases/arel/nodes/window_test.rb +81 -0
  154. data/test/cases/arel/nodes_test.rb +34 -0
  155. data/test/cases/arel/select_manager_test.rb +1238 -0
  156. data/test/cases/arel/support/fake_record.rb +135 -0
  157. data/test/cases/arel/table_test.rb +216 -0
  158. data/test/cases/arel/update_manager_test.rb +126 -0
  159. data/test/cases/arel/visitors/dispatch_contamination_test.rb +78 -0
  160. data/test/cases/arel/visitors/dot_test.rb +90 -0
  161. data/test/cases/arel/visitors/mysql_test.rb +157 -0
  162. data/test/cases/arel/visitors/postgres_test.rb +366 -0
  163. data/test/cases/arel/visitors/sqlite_test.rb +75 -0
  164. data/test/cases/arel/visitors/to_sql_test.rb +750 -0
  165. data/test/cases/associations/belongs_to_associations_test.rb +510 -158
  166. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +4 -2
  167. data/test/cases/associations/callbacks_test.rb +56 -38
  168. data/test/cases/associations/cascaded_eager_loading_test.rb +118 -61
  169. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +138 -18
  170. data/test/cases/associations/eager_load_nested_include_test.rb +38 -37
  171. data/test/cases/associations/eager_singularization_test.rb +21 -21
  172. data/test/cases/associations/eager_test.rb +559 -415
  173. data/test/cases/associations/extension_test.rb +18 -12
  174. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +234 -213
  175. data/test/cases/associations/has_many_associations_test.rb +1038 -465
  176. data/test/cases/associations/has_many_through_associations_test.rb +558 -249
  177. data/test/cases/associations/has_one_associations_test.rb +294 -129
  178. data/test/cases/associations/has_one_through_associations_test.rb +121 -75
  179. data/test/cases/associations/inner_join_association_test.rb +114 -38
  180. data/test/cases/associations/inverse_associations_test.rb +606 -398
  181. data/test/cases/associations/join_model_test.rb +158 -148
  182. data/test/cases/associations/left_outer_join_association_test.rb +59 -24
  183. data/test/cases/associations/nested_through_associations_test.rb +166 -109
  184. data/test/cases/associations/required_test.rb +35 -10
  185. data/test/cases/associations_test.rb +241 -110
  186. data/test/cases/attribute_methods/read_test.rb +11 -11
  187. data/test/cases/attribute_methods_test.rb +413 -298
  188. data/test/cases/attributes_test.rb +145 -27
  189. data/test/cases/autosave_association_test.rb +681 -436
  190. data/test/cases/base_prevent_writes_test.rb +229 -0
  191. data/test/cases/base_test.rb +599 -542
  192. data/test/cases/batches_test.rb +288 -82
  193. data/test/cases/binary_test.rb +26 -31
  194. data/test/cases/bind_parameter_test.rb +194 -21
  195. data/test/cases/boolean_test.rb +52 -0
  196. data/test/cases/cache_key_test.rb +110 -5
  197. data/test/cases/calculations_test.rb +740 -177
  198. data/test/cases/callbacks_test.rb +74 -207
  199. data/test/cases/clone_test.rb +15 -10
  200. data/test/cases/coders/json_test.rb +2 -0
  201. data/test/cases/coders/yaml_column_test.rb +16 -13
  202. data/test/cases/collection_cache_key_test.rb +177 -20
  203. data/test/cases/column_alias_test.rb +9 -7
  204. data/test/cases/column_definition_test.rb +10 -68
  205. data/test/cases/comment_test.rb +166 -107
  206. data/test/cases/connection_adapters/adapter_leasing_test.rb +14 -10
  207. data/test/cases/connection_adapters/connection_handler_test.rb +358 -51
  208. data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +400 -0
  209. data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +103 -0
  210. data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +499 -0
  211. data/test/cases/connection_adapters/connection_swapping_nested_test.rb +457 -0
  212. data/test/cases/connection_adapters/legacy_connection_handlers_multi_db_test.rb +486 -0
  213. data/test/cases/connection_adapters/legacy_connection_handlers_sharding_db_test.rb +586 -0
  214. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +319 -138
  215. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +62 -50
  216. data/test/cases/connection_adapters/schema_cache_test.rb +259 -26
  217. data/test/cases/connection_adapters/type_lookup_test.rb +96 -95
  218. data/test/cases/connection_management_test.rb +13 -11
  219. data/test/cases/connection_pool_test.rb +316 -83
  220. data/test/cases/core_test.rb +82 -58
  221. data/test/cases/counter_cache_test.rb +204 -50
  222. data/test/cases/custom_locking_test.rb +5 -3
  223. data/test/cases/database_configurations/hash_config_test.rb +74 -0
  224. data/test/cases/database_configurations/resolver_test.rb +150 -0
  225. data/test/cases/database_configurations_test.rb +145 -0
  226. data/test/cases/database_selector_test.rb +296 -0
  227. data/test/cases/database_statements_test.rb +18 -16
  228. data/test/cases/date_test.rb +8 -16
  229. data/test/cases/date_time_precision_test.rb +100 -78
  230. data/test/cases/date_time_test.rb +23 -8
  231. data/test/cases/defaults_test.rb +106 -71
  232. data/test/cases/delegated_type_test.rb +57 -0
  233. data/test/cases/dirty_test.rb +419 -223
  234. data/test/cases/disconnected_test.rb +6 -6
  235. data/test/cases/dup_test.rb +54 -27
  236. data/test/cases/enum_test.rb +461 -82
  237. data/test/cases/errors_test.rb +7 -7
  238. data/test/cases/explain_subscriber_test.rb +17 -15
  239. data/test/cases/explain_test.rb +11 -19
  240. data/test/cases/filter_attributes_test.rb +153 -0
  241. data/test/cases/finder_respond_to_test.rb +14 -14
  242. data/test/cases/finder_test.rb +669 -287
  243. data/test/cases/fixture_set/file_test.rb +34 -38
  244. data/test/cases/fixtures_test.rb +833 -176
  245. data/test/cases/forbidden_attributes_protection_test.rb +32 -67
  246. data/test/cases/habtm_destroy_order_test.rb +25 -25
  247. data/test/cases/helper.rb +78 -49
  248. data/test/cases/hot_compatibility_test.rb +33 -32
  249. data/test/cases/i18n_test.rb +18 -17
  250. data/test/cases/inheritance_test.rb +180 -115
  251. data/test/cases/insert_all_test.rb +489 -0
  252. data/test/cases/instrumentation_test.rb +101 -0
  253. data/test/cases/integration_test.rb +119 -31
  254. data/test/cases/invalid_connection_test.rb +18 -16
  255. data/test/cases/invertible_migration_test.rb +183 -43
  256. data/test/cases/json_attribute_test.rb +35 -0
  257. data/test/cases/json_serialization_test.rb +57 -58
  258. data/test/cases/json_shared_test_cases.rb +290 -0
  259. data/test/cases/locking_test.rb +413 -119
  260. data/test/cases/log_subscriber_test.rb +68 -26
  261. data/test/cases/marshal_serialization_test.rb +39 -0
  262. data/test/cases/migration/change_schema_test.rb +118 -72
  263. data/test/cases/migration/change_table_test.rb +138 -30
  264. data/test/cases/migration/check_constraint_test.rb +162 -0
  265. data/test/cases/migration/column_attributes_test.rb +45 -35
  266. data/test/cases/migration/column_positioning_test.rb +18 -6
  267. data/test/cases/migration/columns_test.rb +93 -77
  268. data/test/cases/migration/command_recorder_test.rb +121 -34
  269. data/test/cases/migration/compatibility_test.rb +578 -23
  270. data/test/cases/migration/create_join_table_test.rb +35 -25
  271. data/test/cases/migration/foreign_key_test.rb +503 -284
  272. data/test/cases/migration/helper.rb +4 -3
  273. data/test/cases/migration/index_test.rb +119 -70
  274. data/test/cases/migration/logger_test.rb +9 -6
  275. data/test/cases/migration/pending_migrations_test.rb +88 -34
  276. data/test/cases/migration/references_foreign_key_test.rb +164 -150
  277. data/test/cases/migration/references_index_test.rb +38 -19
  278. data/test/cases/migration/references_statements_test.rb +15 -14
  279. data/test/cases/migration/rename_table_test.rb +53 -30
  280. data/test/cases/migration_test.rb +637 -269
  281. data/test/cases/migrator_test.rb +191 -135
  282. data/test/cases/mixin_test.rb +7 -11
  283. data/test/cases/modules_test.rb +36 -34
  284. data/test/cases/multi_db_migrator_test.rb +223 -0
  285. data/test/cases/multiparameter_attributes_test.rb +60 -33
  286. data/test/cases/multiple_db_test.rb +16 -22
  287. data/test/cases/nested_attributes_test.rb +341 -320
  288. data/test/cases/nested_attributes_with_callbacks_test.rb +26 -24
  289. data/test/cases/null_relation_test.rb +84 -0
  290. data/test/cases/numeric_data_test.rb +93 -0
  291. data/test/cases/persistence_test.rb +361 -269
  292. data/test/cases/pooled_connections_test.rb +18 -26
  293. data/test/cases/prepared_statement_status_test.rb +48 -0
  294. data/test/cases/primary_keys_test.rb +210 -104
  295. data/test/cases/query_cache_test.rb +610 -141
  296. data/test/cases/quoting_test.rb +132 -31
  297. data/test/cases/readonly_test.rb +49 -48
  298. data/test/cases/reaper_test.rb +146 -32
  299. data/test/cases/reflection_test.rb +167 -156
  300. data/test/cases/relation/delegation_test.rb +49 -36
  301. data/test/cases/relation/delete_all_test.rb +117 -0
  302. data/test/cases/relation/merging_test.rb +319 -42
  303. data/test/cases/relation/mutation_test.rb +55 -93
  304. data/test/cases/relation/or_test.rb +129 -29
  305. data/test/cases/relation/predicate_builder_test.rb +21 -6
  306. data/test/cases/relation/record_fetch_warning_test.rb +5 -3
  307. data/test/cases/relation/select_test.rb +67 -0
  308. data/test/cases/relation/update_all_test.rb +317 -0
  309. data/test/cases/relation/where_chain_test.rb +68 -32
  310. data/test/cases/relation/where_clause_test.rb +136 -61
  311. data/test/cases/relation/where_test.rb +155 -48
  312. data/test/cases/relation_test.rb +266 -112
  313. data/test/cases/relations_test.rb +969 -744
  314. data/test/cases/reload_models_test.rb +13 -9
  315. data/test/cases/reserved_word_test.rb +141 -0
  316. data/test/cases/result_test.rb +68 -17
  317. data/test/cases/sanitize_test.rb +87 -71
  318. data/test/cases/schema_dumper_test.rb +221 -128
  319. data/test/cases/schema_loading_test.rb +3 -2
  320. data/test/cases/scoping/default_scoping_test.rb +185 -144
  321. data/test/cases/scoping/named_scoping_test.rb +177 -89
  322. data/test/cases/scoping/relation_scoping_test.rb +197 -75
  323. data/test/cases/secure_token_test.rb +18 -3
  324. data/test/cases/serialization_test.rb +30 -28
  325. data/test/cases/serialized_attribute_test.rb +133 -42
  326. data/test/cases/signed_id_test.rb +168 -0
  327. data/test/cases/statement_cache_test.rb +41 -24
  328. data/test/cases/statement_invalid_test.rb +42 -0
  329. data/test/cases/store_test.rb +180 -55
  330. data/test/cases/strict_loading_test.rb +473 -0
  331. data/test/cases/suppressor_test.rb +26 -12
  332. data/test/cases/tasks/database_tasks_test.rb +1258 -194
  333. data/test/cases/tasks/mysql_rake_test.rb +370 -298
  334. data/test/cases/tasks/postgresql_rake_test.rb +481 -251
  335. data/test/cases/tasks/sqlite_rake_test.rb +225 -178
  336. data/test/cases/test_case.rb +51 -40
  337. data/test/cases/test_databases_test.rb +79 -0
  338. data/test/cases/test_fixtures_test.rb +79 -19
  339. data/test/cases/time_precision_test.rb +98 -76
  340. data/test/cases/timestamp_test.rb +102 -99
  341. data/test/cases/touch_later_test.rb +12 -10
  342. data/test/cases/transaction_callbacks_test.rb +344 -90
  343. data/test/cases/transaction_isolation_test.rb +12 -12
  344. data/test/cases/transactions_test.rb +612 -162
  345. data/test/cases/type/adapter_specific_registry_test.rb +14 -2
  346. data/test/cases/type/date_time_test.rb +4 -2
  347. data/test/cases/type/integer_test.rb +4 -2
  348. data/test/cases/type/string_test.rb +10 -8
  349. data/test/cases/type/time_test.rb +28 -0
  350. data/test/cases/type/type_map_test.rb +29 -28
  351. data/test/cases/type/unsigned_integer_test.rb +19 -0
  352. data/test/cases/type_test.rb +2 -0
  353. data/test/cases/types_test.rb +3 -1
  354. data/test/cases/unconnected_test.rb +14 -1
  355. data/test/cases/unsafe_raw_sql_test.rb +274 -0
  356. data/test/cases/validations/absence_validation_test.rb +19 -17
  357. data/test/cases/validations/association_validation_test.rb +30 -28
  358. data/test/cases/validations/i18n_generate_message_validation_test.rb +34 -16
  359. data/test/cases/validations/i18n_validation_test.rb +22 -21
  360. data/test/cases/validations/length_validation_test.rb +34 -33
  361. data/test/cases/validations/numericality_validation_test.rb +181 -0
  362. data/test/cases/validations/presence_validation_test.rb +21 -19
  363. data/test/cases/validations/uniqueness_validation_test.rb +156 -86
  364. data/test/cases/validations_repair_helper.rb +2 -0
  365. data/test/cases/validations_test.rb +61 -26
  366. data/test/cases/view_test.rb +122 -116
  367. data/test/cases/yaml_serialization_test.rb +79 -34
  368. data/test/config.example.yml +19 -19
  369. data/test/config.rb +3 -1
  370. data/test/config.yml +16 -6
  371. data/test/fixtures/all/namespaced/accounts.yml +2 -0
  372. data/test/fixtures/author_addresses.yml +1 -8
  373. data/test/fixtures/authors.yml +1 -7
  374. data/test/fixtures/binaries.yml +4 -0
  375. data/test/fixtures/books.yml +9 -2
  376. data/test/fixtures/categories_posts.yml +3 -0
  377. data/test/fixtures/citations.yml +5 -0
  378. data/test/fixtures/comments.yml +7 -0
  379. data/test/fixtures/companies.yml +5 -0
  380. data/test/fixtures/computers.yml +2 -0
  381. data/test/fixtures/customers.yml +10 -1
  382. data/test/fixtures/developers.yml +1 -1
  383. data/test/fixtures/essays.yml +10 -0
  384. data/test/fixtures/faces.yml +3 -3
  385. data/test/fixtures/humans.yml +5 -0
  386. data/test/fixtures/interests.yml +7 -7
  387. data/test/fixtures/memberships.yml +7 -0
  388. data/test/fixtures/minimalistics.yml +3 -0
  389. data/test/fixtures/mixed_case_monkeys.yml +2 -2
  390. data/test/fixtures/naked/yml/courses_with_invalid_key.yml +3 -0
  391. data/test/fixtures/naked/yml/parrots.yml +1 -0
  392. data/test/fixtures/other_books.yml +26 -0
  393. data/test/fixtures/other_posts.yml +1 -0
  394. data/test/fixtures/parrots.yml +7 -1
  395. data/test/fixtures/pirates.yml +3 -0
  396. data/test/fixtures/posts.yml +11 -3
  397. data/test/fixtures/readers.yml +6 -0
  398. data/test/fixtures/reserved_words/values.yml +2 -2
  399. data/test/fixtures/sponsors.yml +3 -0
  400. data/test/fixtures/strict_zines.yml +2 -0
  401. data/test/fixtures/subscribers.yml +1 -1
  402. data/test/fixtures/tasks.yml +1 -1
  403. data/test/fixtures/warehouse-things.yml +3 -0
  404. data/test/migrations/10_urban/9_add_expressions.rb +2 -0
  405. data/test/migrations/decimal/1_give_me_big_numbers.rb +6 -4
  406. data/test/migrations/magic/1_currencies_have_symbols.rb +3 -2
  407. data/test/migrations/missing/1000_people_have_middle_names.rb +2 -0
  408. data/test/migrations/missing/1_people_have_last_names.rb +2 -0
  409. data/test/migrations/missing/3_we_need_reminders.rb +2 -0
  410. data/test/migrations/missing/4_innocent_jointable.rb +3 -1
  411. data/test/migrations/rename/1_we_need_things.rb +2 -0
  412. data/test/migrations/rename/2_rename_things.rb +2 -0
  413. data/test/migrations/to_copy/1_people_have_hobbies.rb +3 -1
  414. data/test/migrations/to_copy/2_people_have_descriptions.rb +3 -1
  415. data/test/migrations/to_copy2/1_create_articles.rb +2 -0
  416. data/test/migrations/to_copy2/2_create_comments.rb +3 -1
  417. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +3 -1
  418. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +3 -1
  419. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +3 -1
  420. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +2 -0
  421. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +2 -0
  422. data/test/migrations/valid/1_valid_people_have_last_names.rb +2 -0
  423. data/test/migrations/valid/2_we_need_reminders.rb +2 -0
  424. data/test/migrations/valid/3_innocent_jointable.rb +3 -1
  425. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +2 -0
  426. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +2 -0
  427. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +3 -1
  428. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +2 -0
  429. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +2 -0
  430. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +3 -1
  431. data/test/migrations/version_check/20131219224947_migration_version_check.rb +2 -0
  432. data/test/models/account.rb +46 -0
  433. data/test/models/admin/account.rb +3 -1
  434. data/test/models/admin/randomly_named_c1.rb +2 -0
  435. data/test/models/admin/user.rb +16 -8
  436. data/test/models/admin.rb +4 -2
  437. data/test/models/aircraft.rb +3 -1
  438. data/test/models/arunit2_model.rb +2 -0
  439. data/test/models/author.rb +153 -102
  440. data/test/models/auto_id.rb +2 -0
  441. data/test/models/autoloadable/extra_firm.rb +2 -0
  442. data/test/models/binary.rb +3 -1
  443. data/test/models/binary_field.rb +6 -0
  444. data/test/models/bird.rb +13 -1
  445. data/test/models/book.rb +14 -4
  446. data/test/models/book_destroy_async.rb +24 -0
  447. data/test/models/boolean.rb +5 -0
  448. data/test/models/bulb.rb +13 -4
  449. data/test/models/cake_designer.rb +2 -0
  450. data/test/models/car.rb +17 -10
  451. data/test/models/carrier.rb +2 -0
  452. data/test/models/cart.rb +5 -0
  453. data/test/models/cat.rb +2 -0
  454. data/test/models/categorization.rb +8 -6
  455. data/test/models/category.rb +28 -16
  456. data/test/models/chef.rb +2 -0
  457. data/test/models/citation.rb +5 -1
  458. data/test/models/club.rb +13 -10
  459. data/test/models/college.rb +4 -2
  460. data/test/models/column.rb +2 -0
  461. data/test/models/column_name.rb +2 -0
  462. data/test/models/comment.rb +32 -10
  463. data/test/models/company.rb +102 -106
  464. data/test/models/company_in_module.rb +27 -26
  465. data/test/models/computer.rb +3 -1
  466. data/test/models/contact.rb +15 -13
  467. data/test/models/content.rb +5 -3
  468. data/test/models/contract.rb +21 -3
  469. data/test/models/country.rb +2 -4
  470. data/test/models/course.rb +3 -1
  471. data/test/models/customer.rb +10 -8
  472. data/test/models/customer_carrier.rb +2 -0
  473. data/test/models/dashboard.rb +2 -0
  474. data/test/models/default.rb +2 -0
  475. data/test/models/department.rb +2 -0
  476. data/test/models/destroy_async_parent.rb +15 -0
  477. data/test/models/destroy_async_parent_soft_delete.rb +20 -0
  478. data/test/models/developer.rb +152 -85
  479. data/test/models/dl_keyed_belongs_to.rb +13 -0
  480. data/test/models/dl_keyed_belongs_to_soft_delete.rb +19 -0
  481. data/test/models/dl_keyed_has_many.rb +5 -0
  482. data/test/models/dl_keyed_has_many_through.rb +5 -0
  483. data/test/models/dl_keyed_has_one.rb +5 -0
  484. data/test/models/dl_keyed_join.rb +10 -0
  485. data/test/models/dog.rb +2 -0
  486. data/test/models/dog_lover.rb +2 -0
  487. data/test/models/doubloon.rb +3 -1
  488. data/test/models/drink_designer.rb +17 -0
  489. data/test/models/edge.rb +4 -2
  490. data/test/models/electron.rb +2 -0
  491. data/test/models/engine.rb +3 -2
  492. data/test/models/entrant.rb +2 -0
  493. data/test/models/entry.rb +5 -0
  494. data/test/models/essay.rb +6 -3
  495. data/test/models/essay_destroy_async.rb +12 -0
  496. data/test/models/event.rb +3 -1
  497. data/test/models/eye.rb +5 -3
  498. data/test/models/face.rb +14 -6
  499. data/test/models/family.rb +6 -0
  500. data/test/models/family_tree.rb +6 -0
  501. data/test/models/friendship.rb +5 -3
  502. data/test/models/frog.rb +8 -0
  503. data/test/models/guid.rb +3 -1
  504. data/test/models/guitar.rb +2 -0
  505. data/test/models/hotel.rb +5 -3
  506. data/test/models/human.rb +39 -0
  507. data/test/models/image.rb +3 -1
  508. data/test/models/interest.rb +14 -3
  509. data/test/models/invoice.rb +4 -2
  510. data/test/models/item.rb +3 -1
  511. data/test/models/job.rb +5 -3
  512. data/test/models/joke.rb +4 -2
  513. data/test/models/keyboard.rb +3 -1
  514. data/test/models/legacy_thing.rb +2 -0
  515. data/test/models/lesson.rb +2 -0
  516. data/test/models/line_item.rb +3 -1
  517. data/test/models/liquid.rb +2 -0
  518. data/test/models/matey.rb +3 -1
  519. data/test/models/measurement.rb +4 -0
  520. data/test/models/member.rb +23 -20
  521. data/test/models/member_detail.rb +3 -0
  522. data/test/models/member_type.rb +2 -0
  523. data/test/models/membership.rb +4 -1
  524. data/test/models/mentor.rb +3 -1
  525. data/test/models/message.rb +5 -0
  526. data/test/models/minimalistic.rb +2 -0
  527. data/test/models/minivan.rb +3 -2
  528. data/test/models/mixed_case_monkey.rb +3 -1
  529. data/test/models/molecule.rb +2 -0
  530. data/test/models/mouse.rb +6 -0
  531. data/test/models/movie.rb +2 -0
  532. data/test/models/node.rb +4 -2
  533. data/test/models/non_primary_key.rb +2 -0
  534. data/test/models/notification.rb +2 -0
  535. data/test/models/numeric_data.rb +12 -0
  536. data/test/models/order.rb +4 -2
  537. data/test/models/organization.rb +9 -7
  538. data/test/models/other_dog.rb +3 -1
  539. data/test/models/owner.rb +6 -4
  540. data/test/models/parrot.rb +12 -4
  541. data/test/models/person.rb +59 -54
  542. data/test/models/personal_legacy_thing.rb +3 -1
  543. data/test/models/pet.rb +4 -2
  544. data/test/models/pet_treasure.rb +2 -0
  545. data/test/models/pirate.rb +67 -43
  546. data/test/models/possession.rb +3 -1
  547. data/test/models/post.rb +184 -86
  548. data/test/models/price_estimate.rb +11 -1
  549. data/test/models/professor.rb +3 -1
  550. data/test/models/project.rb +14 -12
  551. data/test/models/publisher/article.rb +2 -0
  552. data/test/models/publisher/magazine.rb +2 -0
  553. data/test/models/publisher.rb +2 -0
  554. data/test/models/randomly_named_c1.rb +2 -0
  555. data/test/models/rating.rb +5 -1
  556. data/test/models/reader.rb +7 -5
  557. data/test/models/recipe.rb +2 -0
  558. data/test/models/record.rb +2 -0
  559. data/test/models/reference.rb +6 -3
  560. data/test/models/reply.rb +39 -21
  561. data/test/models/room.rb +6 -0
  562. data/test/models/section.rb +6 -0
  563. data/test/models/seminar.rb +6 -0
  564. data/test/models/session.rb +6 -0
  565. data/test/models/ship.rb +12 -9
  566. data/test/models/ship_part.rb +5 -3
  567. data/test/models/shop.rb +4 -2
  568. data/test/models/shop_account.rb +2 -0
  569. data/test/models/speedometer.rb +2 -0
  570. data/test/models/sponsor.rb +8 -5
  571. data/test/models/squeak.rb +6 -0
  572. data/test/models/strict_zine.rb +7 -0
  573. data/test/models/string_key_object.rb +2 -0
  574. data/test/models/student.rb +2 -0
  575. data/test/models/subscriber.rb +4 -2
  576. data/test/models/subscription.rb +5 -1
  577. data/test/models/tag.rb +6 -3
  578. data/test/models/tagging.rb +13 -6
  579. data/test/models/task.rb +2 -0
  580. data/test/models/topic.rb +54 -19
  581. data/test/models/toy.rb +4 -0
  582. data/test/models/traffic_light.rb +2 -0
  583. data/test/models/treasure.rb +5 -3
  584. data/test/models/treaty.rb +2 -4
  585. data/test/models/tree.rb +2 -0
  586. data/test/models/tuning_peg.rb +2 -0
  587. data/test/models/tyre.rb +2 -0
  588. data/test/models/user.rb +12 -4
  589. data/test/models/uuid_child.rb +2 -0
  590. data/test/models/uuid_item.rb +2 -0
  591. data/test/models/uuid_parent.rb +2 -0
  592. data/test/models/vegetables.rb +12 -3
  593. data/test/models/vertex.rb +6 -4
  594. data/test/models/warehouse_thing.rb +2 -0
  595. data/test/models/wheel.rb +3 -1
  596. data/test/models/without_table.rb +3 -1
  597. data/test/models/zine.rb +3 -1
  598. data/test/schema/mysql2_specific_schema.rb +49 -35
  599. data/test/schema/oracle_specific_schema.rb +13 -15
  600. data/test/schema/postgresql_specific_schema.rb +51 -40
  601. data/test/schema/schema.rb +334 -154
  602. data/test/schema/sqlite_specific_schema.rb +9 -16
  603. data/test/support/config.rb +26 -26
  604. data/test/support/connection.rb +14 -8
  605. data/test/support/connection_helper.rb +3 -1
  606. data/test/support/ddl_helper.rb +2 -0
  607. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_0_topic.dump +0 -0
  608. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_0_topic_associations.dump +0 -0
  609. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_0_topic.dump +0 -0
  610. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_0_topic_associations.dump +0 -0
  611. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_0_topic.dump +0 -0
  612. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_0_topic_associations.dump +0 -0
  613. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_0_topic.dump +0 -0
  614. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_0_topic_associations.dump +0 -0
  615. data/test/support/marshal_compatibility_fixtures/legacy_6_0_record_mysql.dump +0 -0
  616. data/test/support/marshal_compatibility_fixtures/legacy_relation.dump +0 -0
  617. data/test/support/schema_dumping_helper.rb +2 -0
  618. data/test/support/stubs/strong_parameters.rb +40 -0
  619. data/test/support/yaml_compatibility_fixtures/rails_v1_mysql.yml +206 -0
  620. data/test/support/yaml_compatibility_fixtures/rails_v2.yml +55 -0
  621. metadata +190 -14
@@ -1,44 +1,88 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "cases/helper"
2
- require 'models/post'
3
- require 'models/person'
4
- require 'models/reference'
5
- require 'models/job'
6
- require 'models/reader'
7
- require 'models/comment'
8
- require 'models/rating'
9
- require 'models/tag'
10
- require 'models/tagging'
11
- require 'models/author'
12
- require 'models/owner'
13
- require 'models/pet'
14
- require 'models/pet_treasure'
15
- require 'models/toy'
16
- require 'models/treasure'
17
- require 'models/contract'
18
- require 'models/company'
19
- require 'models/developer'
20
- require 'models/computer'
21
- require 'models/subscriber'
22
- require 'models/book'
23
- require 'models/subscription'
24
- require 'models/essay'
25
- require 'models/category'
26
- require 'models/categorization'
27
- require 'models/member'
28
- require 'models/membership'
29
- require 'models/club'
30
- require 'models/organization'
4
+ require "models/post"
5
+ require "models/person"
6
+ require "models/reference"
7
+ require "models/job"
8
+ require "models/reader"
9
+ require "models/comment"
10
+ require "models/rating"
11
+ require "models/tag"
12
+ require "models/tagging"
13
+ require "models/author"
14
+ require "models/owner"
15
+ require "models/pet"
16
+ require "models/pet_treasure"
17
+ require "models/toy"
18
+ require "models/treasure"
19
+ require "models/contract"
20
+ require "models/company"
21
+ require "models/developer"
22
+ require "models/computer"
23
+ require "models/subscriber"
24
+ require "models/book"
25
+ require "models/subscription"
26
+ require "models/essay"
27
+ require "models/category"
28
+ require "models/categorization"
29
+ require "models/member"
30
+ require "models/membership"
31
+ require "models/club"
32
+ require "models/organization"
33
+ require "models/user"
34
+ require "models/family"
35
+ require "models/family_tree"
36
+ require "models/section"
37
+ require "models/seminar"
38
+ require "models/session"
31
39
 
32
40
  class HasManyThroughAssociationsTest < ActiveRecord::TestCase
33
41
  fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags,
34
42
  :owners, :pets, :toys, :jobs, :references, :companies, :members, :author_addresses,
35
43
  :subscribers, :books, :subscriptions, :developers, :categorizations, :essays,
36
- :categories_posts, :clubs, :memberships, :organizations
44
+ :categories_posts, :clubs, :memberships, :organizations, :author_favorites
37
45
 
38
46
  # Dummies to force column loads so query counts are clean.
39
47
  def setup
40
- Person.create :first_name => 'gummy'
41
- Reader.create :person_id => 0, :post_id => 0
48
+ Person.create first_name: "gummy"
49
+ Reader.create person_id: 0, post_id: 0
50
+ end
51
+
52
+ def test_has_many_through_create_record
53
+ assert books(:awdr).subscribers.create!(nick: "bob")
54
+ end
55
+
56
+ def test_marshal_dump
57
+ preloaded = Post.includes(:first_blue_tags).first
58
+ assert_equal preloaded, Marshal.load(Marshal.dump(preloaded))
59
+ end
60
+
61
+ def test_through_association_with_joins
62
+ assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.merge(Post.joins(:comments))
63
+ end
64
+
65
+ def test_through_association_with_left_joins
66
+ assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.merge(Post.left_joins(:comments))
67
+ end
68
+
69
+ def test_through_association_with_through_scope_and_nested_where
70
+ company = Company.create!(name: "special")
71
+ developer = SpecialDeveloper.create!
72
+ SpecialContract.create!(company: company, special_developer: developer)
73
+
74
+ assert_equal [developer], company.special_developers.where.not("contracts.id": nil)
75
+ end
76
+
77
+ def test_preload_with_nested_association
78
+ posts = Post.where(id: [authors(:david).id, authors(:mary).id]).
79
+ preload(:author, :author_favorites_with_scope).order(:id).to_a
80
+
81
+ assert_no_queries do
82
+ posts.each(&:author)
83
+ posts.each(&:author_favorites_with_scope)
84
+ assert_equal 1, posts[0].author_favorites_with_scope.length
85
+ end
42
86
  end
43
87
 
44
88
  def test_preload_sti_rhs_class
@@ -49,9 +93,9 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
49
93
  end
50
94
 
51
95
  def test_preload_sti_middle_relation
52
- club = Club.create!(name: 'Aaron cool banana club')
53
- member1 = Member.create!(name: 'Aaron')
54
- member2 = Member.create!(name: 'Cat')
96
+ club = Club.create!(name: "Aaron cool banana club")
97
+ member1 = Member.create!(name: "Aaron")
98
+ member2 = Member.create!(name: "Cat")
55
99
 
56
100
  SuperMembership.create! club: club, member: member1
57
101
  CurrentMembership.create! club: club, member: member2
@@ -61,21 +105,26 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
61
105
  club1.members.sort_by(&:id)
62
106
  end
63
107
 
64
- def make_model(name)
65
- Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } }
108
+ def test_preload_multiple_instances_of_the_same_record
109
+ club = Club.create!(name: "Aaron cool banana club")
110
+ Membership.create! club: club, member: Member.create!(name: "Aaron")
111
+ Membership.create! club: club, member: Member.create!(name: "Bob")
112
+
113
+ preloaded_clubs = Club.joins(:memberships).preload(:membership).to_a
114
+ assert_no_queries { preloaded_clubs.each(&:membership) }
66
115
  end
67
116
 
68
- def test_ordered_habtm
117
+ def test_ordered_has_many_through
69
118
  person_prime = Class.new(ActiveRecord::Base) do
70
- def self.name; 'Person'; end
119
+ def self.name; "Person"; end
71
120
 
72
121
  has_many :readers
73
- has_many :posts, -> { order('posts.id DESC') }, :through => :readers
122
+ has_many :posts, -> { order("posts.id DESC") }, through: :readers
74
123
  end
75
124
  posts = person_prime.includes(:posts).first.posts
76
125
 
77
126
  assert_operator posts.length, :>, 1
78
- posts.each_cons(2) do |left,right|
127
+ posts.each_cons(2) do |left, right|
79
128
  assert_operator left.id, :>, right.id
80
129
  end
81
130
  end
@@ -85,7 +134,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
85
134
  subscription = make_model "Subscription"
86
135
  subscriber = make_model "Subscriber"
87
136
 
88
- subscriber.primary_key = 'nick'
137
+ subscriber.primary_key = "nick"
89
138
  subscription.belongs_to :book, anonymous_class: book
90
139
  subscription.belongs_to :subscriber, anonymous_class: subscriber
91
140
 
@@ -106,8 +155,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
106
155
  def test_no_pk_join_table_append
107
156
  lesson, _, student = make_no_pk_hm_t
108
157
 
109
- sicp = lesson.new(:name => "SICP")
110
- ben = student.new(:name => "Ben Bitdiddle")
158
+ sicp = lesson.new(name: "SICP")
159
+ ben = student.new(name: "Ben Bitdiddle")
111
160
  sicp.students << ben
112
161
  assert sicp.save!
113
162
  end
@@ -115,17 +164,17 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
115
164
  def test_no_pk_join_table_delete
116
165
  lesson, lesson_student, student = make_no_pk_hm_t
117
166
 
118
- sicp = lesson.new(:name => "SICP")
119
- ben = student.new(:name => "Ben Bitdiddle")
120
- louis = student.new(:name => "Louis Reasoner")
167
+ sicp = lesson.new(name: "SICP")
168
+ ben = student.new(name: "Ben Bitdiddle")
169
+ louis = student.new(name: "Louis Reasoner")
121
170
  sicp.students << ben
122
171
  sicp.students << louis
123
172
  assert sicp.save!
124
173
 
125
174
  sicp.students.reload
126
175
  assert_operator lesson_student.count, :>=, 2
127
- assert_no_difference('student.count') do
128
- assert_difference('lesson_student.count', -2) do
176
+ assert_no_difference("student.count") do
177
+ assert_difference("lesson_student.count", -2) do
129
178
  sicp.students.destroy(*student.all.to_a)
130
179
  end
131
180
  end
@@ -139,8 +188,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
139
188
  after_destroy_called = true
140
189
  end
141
190
 
142
- sicp = lesson.new(:name => "SICP")
143
- ben = student.new(:name => "Ben Bitdiddle")
191
+ sicp = lesson.new(name: "SICP")
192
+ ben = student.new(name: "Ben Bitdiddle")
144
193
  sicp.students << ben
145
194
  assert sicp.save!
146
195
 
@@ -149,33 +198,19 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
149
198
  assert after_destroy_called, "after destroy should be called"
150
199
  end
151
200
 
152
- def make_no_pk_hm_t
153
- lesson = make_model 'Lesson'
154
- student = make_model 'Student'
155
-
156
- lesson_student = make_model 'LessonStudent'
157
- lesson_student.table_name = 'lessons_students'
158
-
159
- lesson_student.belongs_to :lesson, :anonymous_class => lesson
160
- lesson_student.belongs_to :student, :anonymous_class => student
161
- lesson.has_many :lesson_students, :anonymous_class => lesson_student
162
- lesson.has_many :students, :through => :lesson_students, :anonymous_class => student
163
- [lesson, lesson_student, student]
164
- end
165
-
166
201
  def test_pk_is_not_required_for_join
167
202
  post = Post.includes(:scategories).first
168
203
  post2 = Post.includes(:categories).first
169
204
 
170
205
  assert_operator post.categories.length, :>, 0
171
- assert_equal post2.categories, post.categories
206
+ assert_equal post2.categories.sort_by(&:id), post.categories.sort_by(&:id)
172
207
  end
173
208
 
174
209
  def test_include?
175
210
  person = Person.new
176
211
  post = Post.new
177
212
  person.posts << post
178
- assert person.posts.include?(post)
213
+ assert_includes person.posts, post
179
214
  end
180
215
 
181
216
  def test_associate_existing
@@ -187,19 +222,19 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
187
222
  end
188
223
 
189
224
  assert_queries(1) do
190
- assert post.people.include?(person)
225
+ assert_includes post.people, person
191
226
  end
192
227
 
193
- assert post.reload.people.reload.include?(person)
228
+ assert_includes post.reload.people.reload, person
194
229
  end
195
230
 
196
231
  def test_delete_all_for_with_dependent_option_destroy
197
232
  person = people(:david)
198
233
  assert_equal 1, person.jobs_with_dependent_destroy.count
199
234
 
200
- assert_no_difference 'Job.count' do
201
- assert_difference 'Reference.count', -1 do
202
- person.reload.jobs_with_dependent_destroy.delete_all
235
+ assert_no_difference "Job.count" do
236
+ assert_difference "Reference.count", -1 do
237
+ assert_equal 1, person.reload.jobs_with_dependent_destroy.delete_all
203
238
  end
204
239
  end
205
240
  end
@@ -208,9 +243,9 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
208
243
  person = people(:david)
209
244
  assert_equal 1, person.jobs_with_dependent_nullify.count
210
245
 
211
- assert_no_difference 'Job.count' do
212
- assert_no_difference 'Reference.count' do
213
- person.reload.jobs_with_dependent_nullify.delete_all
246
+ assert_no_difference "Job.count" do
247
+ assert_no_difference "Reference.count" do
248
+ assert_equal 1, person.reload.jobs_with_dependent_nullify.delete_all
214
249
  end
215
250
  end
216
251
  end
@@ -219,26 +254,35 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
219
254
  person = people(:david)
220
255
  assert_equal 1, person.jobs_with_dependent_delete_all.count
221
256
 
222
- assert_no_difference 'Job.count' do
223
- assert_difference 'Reference.count', -1 do
224
- person.reload.jobs_with_dependent_delete_all.delete_all
257
+ assert_no_difference "Job.count" do
258
+ assert_difference "Reference.count", -1 do
259
+ assert_equal 1, person.reload.jobs_with_dependent_delete_all.delete_all
225
260
  end
226
261
  end
227
262
  end
228
263
 
264
+ def test_delete_all_on_association_clears_scope
265
+ post = Post.create!(title: "Rails 6", body: "")
266
+ people = post.people
267
+ people.create!(first_name: "Jeb")
268
+ people.delete_all
269
+ assert_nil people.first
270
+ end
271
+
229
272
  def test_concat
230
273
  person = people(:david)
231
274
  post = posts(:thinking)
232
- post.people.concat [person]
275
+ result = post.people.concat [person]
233
276
  assert_equal 1, post.people.size
234
277
  assert_equal 1, post.people.reload.size
278
+ assert_equal post.people, result
235
279
  end
236
280
 
237
281
  def test_associate_existing_record_twice_should_add_to_target_twice
238
282
  post = posts(:thinking)
239
283
  person = people(:david)
240
284
 
241
- assert_difference 'post.people.to_a.count', 2 do
285
+ assert_difference "post.people.to_a.count", 2 do
242
286
  post.people << person
243
287
  post.people << person
244
288
  end
@@ -248,7 +292,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
248
292
  post = posts(:thinking)
249
293
  person = people(:david)
250
294
 
251
- assert_difference 'post.people.count', 2 do
295
+ assert_difference "post.people.count", 2 do
252
296
  post.people << person
253
297
  post.people << person
254
298
  end
@@ -261,12 +305,12 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
261
305
  post.people << person
262
306
  post.people << person
263
307
 
264
- counts = ['post.people.count', 'post.people.to_a.count', 'post.readers.count', 'post.readers.to_a.count']
308
+ counts = ["post.people.count", "post.people.to_a.count", "post.readers.count", "post.readers.to_a.count"]
265
309
  assert_difference counts, -2 do
266
310
  post.people.delete(person)
267
311
  end
268
312
 
269
- assert !post.people.reload.include?(person)
313
+ assert_not_includes post.people.reload, person
270
314
  end
271
315
 
272
316
  def test_associating_new
@@ -274,7 +318,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
274
318
  new_person = nil # so block binding catches it
275
319
 
276
320
  assert_queries(0) do
277
- new_person = Person.new :first_name => 'bob'
321
+ new_person = Person.new first_name: "bob"
278
322
  end
279
323
 
280
324
  # Associating new records always saves them
@@ -284,59 +328,70 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
284
328
  end
285
329
 
286
330
  assert_queries(1) do
287
- assert posts(:thinking).people.include?(new_person)
331
+ assert_includes posts(:thinking).people, new_person
288
332
  end
289
333
 
290
- assert posts(:thinking).reload.people.reload.include?(new_person)
334
+ assert_includes posts(:thinking).reload.people.reload, new_person
291
335
  end
292
336
 
293
337
  def test_associate_new_by_building
294
338
  assert_queries(1) { posts(:thinking) }
295
339
 
296
340
  assert_queries(0) do
297
- posts(:thinking).people.build(:first_name => "Bob")
298
- posts(:thinking).people.new(:first_name => "Ted")
341
+ posts(:thinking).people.build(first_name: "Bob")
342
+ posts(:thinking).people.new(first_name: "Ted")
299
343
  end
300
344
 
301
345
  # Should only need to load the association once
302
346
  assert_queries(1) do
303
- assert posts(:thinking).people.collect(&:first_name).include?("Bob")
304
- assert posts(:thinking).people.collect(&:first_name).include?("Ted")
347
+ assert_includes posts(:thinking).people.collect(&:first_name), "Bob"
348
+ assert_includes posts(:thinking).people.collect(&:first_name), "Ted"
305
349
  end
306
350
 
307
351
  # 2 queries for each new record (1 to save the record itself, 1 for the join model)
308
352
  # * 2 new records = 4
309
353
  # + 1 query to save the actual post = 5
310
354
  assert_queries(5) do
311
- posts(:thinking).body += '-changed'
355
+ posts(:thinking).body += "-changed"
312
356
  posts(:thinking).save
313
357
  end
314
358
 
315
- assert posts(:thinking).reload.people.reload.collect(&:first_name).include?("Bob")
316
- assert posts(:thinking).reload.people.reload.collect(&:first_name).include?("Ted")
359
+ assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Bob"
360
+ assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Ted"
317
361
  end
318
362
 
319
363
  def test_build_then_save_with_has_many_inverse
320
364
  post = posts(:thinking)
321
- person = post.people.build(:first_name => "Bob")
365
+ person = post.people.build(first_name: "Bob")
322
366
  person.save
323
367
  post.reload
324
368
 
325
- assert post.people.include?(person)
369
+ assert_includes post.people, person
326
370
  end
327
371
 
328
372
  def test_build_then_save_with_has_one_inverse
329
373
  post = posts(:thinking)
330
- person = post.single_people.build(:first_name => "Bob")
374
+ person = post.single_people.build(first_name: "Bob")
331
375
  person.save
332
376
  post.reload
333
377
 
334
- assert post.single_people.include?(person)
378
+ assert_includes post.single_people, person
379
+ end
380
+
381
+ def test_build_then_remove_then_save
382
+ post = posts(:thinking)
383
+ post.people.build(first_name: "Bob")
384
+ ted = post.people.build(first_name: "Ted")
385
+ post.people.delete(ted)
386
+ post.save!
387
+ post.reload
388
+
389
+ assert_equal ["Bob"], post.people.collect(&:first_name)
335
390
  end
336
391
 
337
392
  def test_both_parent_ids_set_when_saving_new
338
- post = Post.new(title: 'Hello', body: 'world')
339
- person = Person.new(first_name: 'Sean')
393
+ post = Post.new(title: "Hello", body: "world")
394
+ person = Person.new(first_name: "Sean")
340
395
 
341
396
  post.people = [person]
342
397
  post.save
@@ -348,17 +403,17 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
348
403
  end
349
404
 
350
405
  def test_delete_association
351
- assert_queries(2){posts(:welcome);people(:michael); }
406
+ assert_queries(2) { posts(:welcome); people(:michael); }
352
407
 
353
408
  assert_queries(1) do
354
409
  posts(:welcome).people.delete(people(:michael))
355
410
  end
356
411
 
357
412
  assert_queries(1) do
358
- assert posts(:welcome).people.empty?
413
+ assert_empty posts(:welcome).people
359
414
  end
360
415
 
361
- assert posts(:welcome).reload.people.reload.empty?
416
+ assert_empty posts(:welcome).reload.people.reload
362
417
  end
363
418
 
364
419
  def test_destroy_association
@@ -368,8 +423,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
368
423
  end
369
424
  end
370
425
 
371
- assert posts(:welcome).reload.people.empty?
372
- assert posts(:welcome).people.reload.empty?
426
+ assert_empty posts(:welcome).reload.people
427
+ assert_empty posts(:welcome).people.reload
373
428
  end
374
429
 
375
430
  def test_destroy_all
@@ -379,8 +434,32 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
379
434
  end
380
435
  end
381
436
 
382
- assert posts(:welcome).reload.people.empty?
383
- assert posts(:welcome).people.reload.empty?
437
+ assert_empty posts(:welcome).reload.people
438
+ assert_empty posts(:welcome).people.reload
439
+ end
440
+
441
+ def test_destroy_all_on_association_clears_scope
442
+ post = Post.create!(title: "Rails 6", body: "")
443
+ people = post.people
444
+ people.create!(first_name: "Jeb")
445
+ people.destroy_all
446
+ assert_nil people.first
447
+ end
448
+
449
+ def test_destroy_on_association_clears_scope
450
+ post = Post.create!(title: "Rails 6", body: "")
451
+ people = post.people
452
+ person = people.create!(first_name: "Jeb")
453
+ people.destroy(person)
454
+ assert_nil people.first
455
+ end
456
+
457
+ def test_delete_on_association_clears_scope
458
+ post = Post.create!(title: "Rails 6", body: "")
459
+ people = post.people
460
+ person = people.create!(first_name: "Jeb")
461
+ people.delete(person)
462
+ assert_nil people.first
384
463
  end
385
464
 
386
465
  def test_should_raise_exception_for_destroying_mismatching_records
@@ -394,15 +473,15 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
394
473
 
395
474
  person = people(:michael)
396
475
  job = jobs(:magician)
397
- reference = Reference.where(:job_id => job.id, :person_id => person.id).first
476
+ reference = Reference.where(job_id: job.id, person_id: person.id).first
398
477
 
399
- assert_no_difference ['Job.count', 'Reference.count'] do
400
- assert_difference 'person.jobs.count', -1 do
478
+ assert_no_difference ["Job.count", "Reference.count"] do
479
+ assert_difference "person.jobs.count", -1 do
401
480
  person.jobs_with_dependent_nullify.delete(job)
402
481
  end
403
482
  end
404
483
 
405
- assert_equal nil, reference.reload.job_id
484
+ assert_nil reference.reload.job_id
406
485
  ensure
407
486
  Reference.make_comments = false
408
487
  end
@@ -416,14 +495,14 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
416
495
  # Make sure we're not deleting everything
417
496
  assert person.jobs.count >= 2
418
497
 
419
- assert_no_difference 'Job.count' do
420
- assert_difference ['person.jobs.count', 'Reference.count'], -1 do
498
+ assert_no_difference "Job.count" do
499
+ assert_difference ["person.jobs.count", "Reference.count"], -1 do
421
500
  person.jobs_with_dependent_delete_all.delete(job)
422
501
  end
423
502
  end
424
503
 
425
504
  # Check that the destroy callback on Reference did not run
426
- assert_equal nil, person.reload.comments
505
+ assert_nil person.reload.comments
427
506
  ensure
428
507
  Reference.make_comments = false
429
508
  end
@@ -437,8 +516,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
437
516
  # Make sure we're not deleting everything
438
517
  assert person.jobs.count >= 2
439
518
 
440
- assert_no_difference 'Job.count' do
441
- assert_difference ['person.jobs.count', 'Reference.count'], -1 do
519
+ assert_no_difference "Job.count" do
520
+ assert_difference ["person.jobs.count", "Reference.count"], -1 do
442
521
  person.jobs_with_dependent_destroy.delete(job)
443
522
  end
444
523
  end
@@ -455,8 +534,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
455
534
  # Create a reference which is not linked to a job. This should not be destroyed.
456
535
  person.references.create!
457
536
 
458
- assert_no_difference 'Job.count' do
459
- assert_difference 'Reference.count', -person.jobs.count do
537
+ assert_no_difference "Job.count" do
538
+ assert_difference "Reference.count", -person.jobs.count do
460
539
  person.destroy
461
540
  end
462
541
  end
@@ -468,8 +547,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
468
547
  # Create a reference which is not linked to a job. This should not be destroyed.
469
548
  person.references.create!
470
549
 
471
- assert_no_difference 'Job.count' do
472
- assert_difference 'Reference.count', -person.jobs.count do
550
+ assert_no_difference "Job.count" do
551
+ assert_difference "Reference.count", -person.jobs.count do
473
552
  person.destroy
474
553
  end
475
554
  end
@@ -480,41 +559,41 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
480
559
 
481
560
  references = person.references.to_a
482
561
 
483
- assert_no_difference ['Reference.count', 'Job.count'] do
562
+ assert_no_difference ["Reference.count", "Job.count"] do
484
563
  person.destroy
485
564
  end
486
565
 
487
566
  references.each do |reference|
488
- assert_equal nil, reference.reload.job_id
567
+ assert_nil reference.reload.job_id
489
568
  end
490
569
  end
491
570
 
492
571
  def test_update_counter_caches_on_delete
493
572
  post = posts(:welcome)
494
- tag = post.tags.create!(:name => 'doomed')
573
+ tag = post.tags.create!(name: "doomed")
495
574
 
496
- assert_difference ['post.reload.tags_count'], -1 do
575
+ assert_difference ["post.reload.tags_count"], -1 do
497
576
  posts(:welcome).tags.delete(tag)
498
577
  end
499
578
  end
500
579
 
501
580
  def test_update_counter_caches_on_delete_with_dependent_destroy
502
581
  post = posts(:welcome)
503
- tag = post.tags.create!(:name => 'doomed')
582
+ tag = post.tags.create!(name: "doomed")
504
583
  post.update_columns(tags_with_destroy_count: post.tags.count)
505
584
 
506
- assert_difference ['post.reload.tags_with_destroy_count'], -1 do
585
+ assert_difference ["post.reload.tags_with_destroy_count"], -1 do
507
586
  posts(:welcome).tags_with_destroy.delete(tag)
508
587
  end
509
588
  end
510
589
 
511
590
  def test_update_counter_caches_on_delete_with_dependent_nullify
512
591
  post = posts(:welcome)
513
- tag = post.tags.create!(:name => 'doomed')
592
+ tag = post.tags.create!(name: "doomed")
514
593
  post.update_columns(tags_with_nullify_count: post.tags.count)
515
594
 
516
- assert_no_difference 'post.reload.tags_count' do
517
- assert_difference 'post.reload.tags_with_nullify_count', -1 do
595
+ assert_no_difference "post.reload.tags_count" do
596
+ assert_difference "post.reload.tags_with_nullify_count", -1 do
518
597
  posts(:welcome).tags_with_nullify.delete(tag)
519
598
  end
520
599
  end
@@ -522,7 +601,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
522
601
 
523
602
  def test_update_counter_caches_on_replace_association
524
603
  post = posts(:welcome)
525
- tag = post.tags.create!(:name => 'doomed')
604
+ tag = post.tags.create!(name: "doomed")
526
605
  tag.tagged_posts << posts(:thinking)
527
606
 
528
607
  tag.tagged_posts = []
@@ -533,15 +612,25 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
533
612
 
534
613
  def test_update_counter_caches_on_destroy
535
614
  post = posts(:welcome)
536
- tag = post.tags.create!(name: 'doomed')
615
+ tag = post.tags.create!(name: "doomed")
537
616
 
538
- assert_difference 'post.reload.tags_count', -1 do
617
+ assert_difference "post.reload.tags_count", -1 do
539
618
  tag.tagged_posts.destroy(post)
540
619
  end
541
620
  end
542
621
 
622
+ def test_update_counter_caches_on_destroy_with_indestructible_through_record
623
+ post = posts(:welcome)
624
+ tag = post.indestructible_tags.create!(name: "doomed")
625
+ post.update_columns(indestructible_tags_count: post.indestructible_tags.count)
626
+
627
+ assert_no_difference "post.reload.indestructible_tags_count" do
628
+ posts(:welcome).indestructible_tags.destroy(tag)
629
+ end
630
+ end
631
+
543
632
  def test_replace_association
544
- assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people.reload}
633
+ assert_queries(4) { posts(:welcome); people(:david); people(:michael); posts(:welcome).people.reload }
545
634
 
546
635
  # 1 query to delete the existing reader (michael)
547
636
  # 1 query to associate the new reader (david)
@@ -549,35 +638,45 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
549
638
  posts(:welcome).people = [people(:david)]
550
639
  end
551
640
 
552
- assert_queries(0){
553
- assert posts(:welcome).people.include?(people(:david))
554
- assert !posts(:welcome).people.include?(people(:michael))
555
- }
641
+ assert_no_queries do
642
+ assert_includes posts(:welcome).people, people(:david)
643
+ assert_not_includes posts(:welcome).people, people(:michael)
644
+ end
645
+
646
+ assert_includes posts(:welcome).reload.people.reload, people(:david)
647
+ assert_not_includes posts(:welcome).reload.people.reload, people(:michael)
648
+ end
556
649
 
557
- assert posts(:welcome).reload.people.reload.include?(people(:david))
558
- assert !posts(:welcome).reload.people.reload.include?(people(:michael))
650
+ def test_replace_association_with_duplicates
651
+ post = posts(:thinking)
652
+ person = people(:david)
653
+
654
+ assert_difference "post.people.count", 2 do
655
+ post.people = [person]
656
+ post.people = [person, person]
657
+ end
559
658
  end
560
659
 
561
660
  def test_replace_order_is_preserved
562
661
  posts(:welcome).people.clear
563
662
  posts(:welcome).people = [people(:david), people(:michael)]
564
- assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id)
663
+ assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order("id").map(&:person_id)
565
664
 
566
665
  # Test the inverse order in case the first success was a coincidence
567
666
  posts(:welcome).people.clear
568
667
  posts(:welcome).people = [people(:michael), people(:david)]
569
- assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id)
668
+ assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order("id").map(&:person_id)
570
669
  end
571
670
 
572
671
  def test_replace_by_id_order_is_preserved
573
672
  posts(:welcome).people.clear
574
673
  posts(:welcome).person_ids = [people(:david).id, people(:michael).id]
575
- assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id)
674
+ assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order("id").map(&:person_id)
576
675
 
577
676
  # Test the inverse order in case the first success was a coincidence
578
677
  posts(:welcome).people.clear
579
678
  posts(:welcome).person_ids = [people(:michael).id, people(:david).id]
580
- assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id)
679
+ assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order("id").map(&:person_id)
581
680
  end
582
681
 
583
682
  def test_associate_with_create
@@ -586,101 +685,107 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
586
685
  # 1 query for the new record, 1 for the join table record
587
686
  # No need to update the actual collection yet!
588
687
  assert_queries(2) do
589
- posts(:thinking).people.create(:first_name=>"Jeb")
688
+ posts(:thinking).people.create(first_name: "Jeb")
590
689
  end
591
690
 
592
691
  # *Now* we actually need the collection so it's loaded
593
692
  assert_queries(1) do
594
- assert posts(:thinking).people.collect(&:first_name).include?("Jeb")
693
+ assert_includes posts(:thinking).people.collect(&:first_name), "Jeb"
595
694
  end
596
695
 
597
- assert posts(:thinking).reload.people.reload.collect(&:first_name).include?("Jeb")
696
+ assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Jeb"
598
697
  end
599
698
 
600
699
  def test_through_record_is_built_when_created_with_where
601
700
  assert_difference("posts(:thinking).readers.count", 1) do
602
- posts(:thinking).people.where(first_name: "Jeb").create
701
+ posts(:thinking).people.where(readers: { skimmer: true }).create(first_name: "Jeb")
603
702
  end
703
+ reader = posts(:thinking).readers.last
704
+ assert_equal true, reader.skimmer
604
705
  end
605
706
 
606
707
  def test_associate_with_create_and_no_options
607
708
  peeps = posts(:thinking).people.count
608
- posts(:thinking).people.create(:first_name => 'foo')
709
+ posts(:thinking).people.create(first_name: "foo")
609
710
  assert_equal peeps + 1, posts(:thinking).people.count
610
711
  end
611
712
 
612
713
  def test_associate_with_create_with_through_having_conditions
613
714
  impatient_people = posts(:thinking).impatient_people.count
614
- posts(:thinking).impatient_people.create!(:first_name => 'foo')
715
+ posts(:thinking).impatient_people.create!(first_name: "foo")
615
716
  assert_equal impatient_people + 1, posts(:thinking).impatient_people.count
616
717
  end
617
718
 
618
719
  def test_associate_with_create_exclamation_and_no_options
619
720
  peeps = posts(:thinking).people.count
620
- posts(:thinking).people.create!(:first_name => 'foo')
721
+ posts(:thinking).people.create!(first_name: "foo")
621
722
  assert_equal peeps + 1, posts(:thinking).people.count
622
723
  end
623
724
 
624
725
  def test_create_on_new_record
625
726
  p = Post.new
626
727
 
627
- error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create(:first_name => "mew") }
728
+ error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create(first_name: "mew") }
628
729
  assert_equal "You cannot call create unless the parent is saved", error.message
629
730
 
630
- error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create!(:first_name => "snow") }
731
+ error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create!(first_name: "snow") }
631
732
  assert_equal "You cannot call create unless the parent is saved", error.message
632
733
  end
633
734
 
634
735
  def test_associate_with_create_and_invalid_options
635
736
  firm = companies(:first_firm)
636
- assert_no_difference('firm.developers.count') { assert_nothing_raised { firm.developers.create(:name => '0') } }
737
+ assert_no_difference("firm.developers.count") { assert_nothing_raised { firm.developers.create(name: "0") } }
637
738
  end
638
739
 
639
740
  def test_associate_with_create_and_valid_options
640
741
  firm = companies(:first_firm)
641
- assert_difference('firm.developers.count', 1) { firm.developers.create(:name => 'developer') }
742
+ assert_difference("firm.developers.count", 1) { firm.developers.create(name: "developer") }
642
743
  end
643
744
 
644
745
  def test_associate_with_create_bang_and_invalid_options
645
746
  firm = companies(:first_firm)
646
- assert_no_difference('firm.developers.count') { assert_raises(ActiveRecord::RecordInvalid) { firm.developers.create!(:name => '0') } }
747
+ assert_no_difference("firm.developers.count") { assert_raises(ActiveRecord::RecordInvalid) { firm.developers.create!(name: "0") } }
647
748
  end
648
749
 
649
750
  def test_associate_with_create_bang_and_valid_options
650
751
  firm = companies(:first_firm)
651
- assert_difference('firm.developers.count', 1) { firm.developers.create!(:name => 'developer') }
752
+ assert_difference("firm.developers.count", 1) { firm.developers.create!(name: "developer") }
652
753
  end
653
754
 
654
755
  def test_push_with_invalid_record
655
756
  firm = companies(:first_firm)
656
- assert_raises(ActiveRecord::RecordInvalid) { firm.developers << Developer.new(:name => '0') }
757
+ assert_raises(ActiveRecord::RecordInvalid) { firm.developers << Developer.new(name: "0") }
657
758
  end
658
759
 
659
760
  def test_push_with_invalid_join_record
660
761
  repair_validations(Contract) do
661
- Contract.validate {|r| r.errors[:base] << 'Invalid Contract' }
762
+ Contract.validate { |r| r.errors[:base] << "Invalid Contract" }
662
763
 
663
764
  firm = companies(:first_firm)
664
- lifo = Developer.new(:name => 'lifo')
665
- assert_raises(ActiveRecord::RecordInvalid) { firm.developers << lifo }
765
+ lifo = Developer.new(name: "lifo")
766
+ assert_raises(ActiveRecord::RecordInvalid) do
767
+ assert_deprecated { firm.developers << lifo }
768
+ end
666
769
 
667
- lifo = Developer.create!(:name => 'lifo')
668
- assert_raises(ActiveRecord::RecordInvalid) { firm.developers << lifo }
770
+ lifo = Developer.create!(name: "lifo")
771
+ assert_raises(ActiveRecord::RecordInvalid) do
772
+ assert_deprecated { firm.developers << lifo }
773
+ end
669
774
  end
670
775
  end
671
776
 
672
777
  def test_clear_associations
673
- assert_queries(2) { posts(:welcome);posts(:welcome).people.reload }
778
+ assert_queries(2) { posts(:welcome); posts(:welcome).people.reload }
674
779
 
675
780
  assert_queries(1) do
676
781
  posts(:welcome).people.clear
677
782
  end
678
783
 
679
- assert_queries(0) do
680
- assert posts(:welcome).people.empty?
784
+ assert_no_queries do
785
+ assert_empty posts(:welcome).people
681
786
  end
682
787
 
683
- assert posts(:welcome).reload.people.reload.empty?
788
+ assert_empty posts(:welcome).reload.people.reload
684
789
  end
685
790
 
686
791
  def test_association_callback_ordering
@@ -694,7 +799,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
694
799
  [:added, :after, "Michael"]
695
800
  ], log.last(2)
696
801
 
697
- post.people_with_callbacks.push(people(:david), Person.create!(:first_name => "Bob"), Person.new(:first_name => "Lary"))
802
+ post.people_with_callbacks.push(people(:david), Person.create!(first_name: "Bob"), Person.new(first_name: "Lary"))
698
803
  assert_equal [
699
804
  [:added, :before, "David"],
700
805
  [:added, :after, "David"],
@@ -702,21 +807,21 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
702
807
  [:added, :after, "Bob"],
703
808
  [:added, :before, "Lary"],
704
809
  [:added, :after, "Lary"]
705
- ],log.last(6)
810
+ ], log.last(6)
706
811
 
707
- post.people_with_callbacks.build(:first_name => "Ted")
812
+ post.people_with_callbacks.build(first_name: "Ted")
708
813
  assert_equal [
709
814
  [:added, :before, "Ted"],
710
815
  [:added, :after, "Ted"]
711
816
  ], log.last(2)
712
817
 
713
- post.people_with_callbacks.create(:first_name => "Sam")
818
+ post.people_with_callbacks.create(first_name: "Sam")
714
819
  assert_equal [
715
820
  [:added, :before, "Sam"],
716
821
  [:added, :after, "Sam"]
717
822
  ], log.last(2)
718
823
 
719
- post.people_with_callbacks = [people(:michael),people(:david), Person.new(:first_name => "Julian"), Person.create!(:first_name => "Roger")]
824
+ post.people_with_callbacks = [people(:michael), people(:david), Person.new(first_name: "Julian"), Person.create!(first_name: "Roger")]
720
825
  assert_equal((%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort)
721
826
  assert_equal [
722
827
  [:added, :before, "Julian"],
@@ -724,12 +829,24 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
724
829
  [:added, :before, "Roger"],
725
830
  [:added, :after, "Roger"]
726
831
  ], log.last(4)
832
+
833
+ post.people_with_callbacks.build { |person| person.first_name = "Ted" }
834
+ assert_equal [
835
+ [:added, :before, "Ted"],
836
+ [:added, :after, "Ted"]
837
+ ], log.last(2)
838
+
839
+ post.people_with_callbacks.create { |person| person.first_name = "Sam" }
840
+ assert_equal [
841
+ [:added, :before, "Sam"],
842
+ [:added, :after, "Sam"]
843
+ ], log.last(2)
727
844
  end
728
845
 
729
846
  def test_dynamic_find_should_respect_association_include
730
847
  # SQL error in sort clause if :include is not included
731
848
  # due to Unknown column 'comments.id'
732
- assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title('Welcome to the weblog')
849
+ assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title("Welcome to the weblog")
733
850
  end
734
851
 
735
852
  def test_count_with_include_should_alias_join_table
@@ -745,7 +862,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
745
862
  end
746
863
 
747
864
  def test_get_ids_for_has_many_through_with_conditions_should_not_preload
748
- Tagging.create!(:taggable_type => 'Post', :taggable_id => posts(:welcome).id, :tag => tags(:misc))
865
+ Tagging.create!(taggable_type: "Post", taggable_id: posts(:welcome).id, tag: tags(:misc))
749
866
  assert_not_called(ActiveRecord::Associations::Preloader, :new) do
750
867
  posts(:welcome).misc_tag_ids
751
868
  end
@@ -754,7 +871,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
754
871
  def test_get_ids_for_loaded_associations
755
872
  person = people(:michael)
756
873
  person.posts.reload
757
- assert_queries(0) do
874
+ assert_no_queries do
758
875
  person.post_ids
759
876
  person.post_ids
760
877
  end
@@ -762,9 +879,9 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
762
879
 
763
880
  def test_get_ids_for_unloaded_associations_does_not_load_them
764
881
  person = people(:michael)
765
- assert !person.posts.loaded?
882
+ assert_not_predicate person.posts, :loaded?
766
883
  assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort
767
- assert !person.posts.loaded?
884
+ assert_not_predicate person.posts, :loaded?
768
885
  end
769
886
 
770
887
  def test_association_proxy_transaction_method_starts_transaction_in_association_class
@@ -776,16 +893,16 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
776
893
  end
777
894
 
778
895
  def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist
779
- post = Post.create!(:title => "TITLE", :body => "BODY")
896
+ post = Post.create!(title: "TITLE", body: "BODY")
780
897
  assert_equal [], post.author_favorites
781
898
  end
782
899
 
783
900
  def test_has_many_association_through_a_belongs_to_association
784
901
  author = authors(:mary)
785
- post = Post.create!(:author => author, :title => "TITLE", :body => "BODY")
786
- author.author_favorites.create(:favorite_author_id => 1)
787
- author.author_favorites.create(:favorite_author_id => 2)
788
- author.author_favorites.create(:favorite_author_id => 3)
902
+ post = Post.create!(author: author, title: "TITLE", body: "BODY")
903
+ author.author_favorites.create(favorite_author_id: 1)
904
+ author.author_favorites.create(favorite_author_id: 2)
905
+ author.author_favorites.create(favorite_author_id: 3)
789
906
  assert_equal post.author.author_favorites, post.author_favorites
790
907
  end
791
908
 
@@ -809,37 +926,37 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
809
926
 
810
927
  def test_modifying_has_many_through_has_one_reflection_should_raise
811
928
  [
812
- lambda { authors(:david).very_special_comments = [VerySpecialComment.create!(:body => "Gorp!", :post_id => 1011), VerySpecialComment.create!(:body => "Eep!", :post_id => 1012)] },
813
- lambda { authors(:david).very_special_comments << VerySpecialComment.create!(:body => "Hoohah!", :post_id => 1013) },
929
+ lambda { authors(:david).very_special_comments = [VerySpecialComment.create!(body: "Gorp!", post_id: 1011), VerySpecialComment.create!(body: "Eep!", post_id: 1012)] },
930
+ lambda { authors(:david).very_special_comments << VerySpecialComment.create!(body: "Hoohah!", post_id: 1013) },
814
931
  lambda { authors(:david).very_special_comments.delete(authors(:david).very_special_comments.first) },
815
- ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
932
+ ].each { |block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
816
933
  end
817
934
 
818
935
  def test_has_many_association_through_a_has_many_association_to_self
819
- sarah = Person.create!(:first_name => 'Sarah', :primary_contact_id => people(:susan).id, :gender => 'F', :number1_fan_id => 1)
820
- john = Person.create!(:first_name => 'John', :primary_contact_id => sarah.id, :gender => 'M', :number1_fan_id => 1)
936
+ sarah = Person.create!(first_name: "Sarah", primary_contact_id: people(:susan).id, gender: "F", number1_fan_id: 1)
937
+ john = Person.create!(first_name: "John", primary_contact_id: sarah.id, gender: "M", number1_fan_id: 1)
821
938
  assert_equal sarah.agents, [john]
822
- assert_equal people(:susan).agents.flat_map(&:agents), people(:susan).agents_of_agents
939
+ assert_equal people(:susan).agents.flat_map(&:agents).sort, people(:susan).agents_of_agents.sort
823
940
  end
824
941
 
825
942
  def test_associate_existing_with_nonstandard_primary_key_on_belongs_to
826
- Categorization.create(:author => authors(:mary), :named_category_name => categories(:general).name)
943
+ Categorization.create(author: authors(:mary), named_category_name: categories(:general).name)
827
944
  assert_equal categories(:general), authors(:mary).named_categories.first
828
945
  end
829
946
 
830
947
  def test_collection_build_with_nonstandard_primary_key_on_belongs_to
831
948
  author = authors(:mary)
832
- category = author.named_categories.build(:name => "Primary")
949
+ category = author.named_categories.build(name: "Primary")
833
950
  author.save
834
- assert Categorization.exists?(:author_id => author.id, :named_category_name => category.name)
835
- assert author.named_categories.reload.include?(category)
951
+ assert Categorization.exists?(author_id: author.id, named_category_name: category.name)
952
+ assert_includes author.named_categories.reload, category
836
953
  end
837
954
 
838
955
  def test_collection_create_with_nonstandard_primary_key_on_belongs_to
839
956
  author = authors(:mary)
840
- category = author.named_categories.create(:name => "Primary")
841
- assert Categorization.exists?(:author_id => author.id, :named_category_name => category.name)
842
- assert author.named_categories.reload.include?(category)
957
+ category = author.named_categories.create(name: "Primary")
958
+ assert Categorization.exists?(author_id: author.id, named_category_name: category.name)
959
+ assert_includes author.named_categories.reload, category
843
960
  end
844
961
 
845
962
  def test_collection_exists
@@ -851,10 +968,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
851
968
 
852
969
  def test_collection_delete_with_nonstandard_primary_key_on_belongs_to
853
970
  author = authors(:mary)
854
- category = author.named_categories.create(:name => "Primary")
971
+ category = author.named_categories.create(name: "Primary")
855
972
  author.named_categories.delete(category)
856
- assert !Categorization.exists?(:author_id => author.id, :named_category_name => category.name)
857
- assert author.named_categories.reload.empty?
973
+ assert_not Categorization.exists?(author_id: author.id, named_category_name: category.name)
974
+ assert_empty author.named_categories.reload
858
975
  end
859
976
 
860
977
  def test_collection_singular_ids_getter_with_string_primary_keys
@@ -871,6 +988,14 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
871
988
  assert_equal [dev], company.developers
872
989
  end
873
990
 
991
+ def test_collection_singular_ids_setter_with_required_type_cast
992
+ company = companies(:rails_core)
993
+ dev = Developer.first
994
+
995
+ company.developer_ids = [dev.id.to_s]
996
+ assert_equal [dev], company.developers
997
+ end
998
+
874
999
  def test_collection_singular_ids_setter_with_string_primary_keys
875
1000
  assert_nothing_raised do
876
1001
  book = books(:awdr)
@@ -880,34 +1005,35 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
880
1005
  book.subscriber_ids = []
881
1006
  assert_equal [], book.subscribers.reload
882
1007
  end
883
-
884
1008
  end
885
1009
 
886
1010
  def test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set
887
1011
  company = companies(:rails_core)
888
1012
  ids = [Developer.first.id, -9999]
889
1013
  e = assert_raises(ActiveRecord::RecordNotFound) { company.developer_ids = ids }
890
- assert_match(/Couldn't find all Developers with 'id'/, e.message)
1014
+ msg = "Couldn't find all Developers with 'id': (1, -9999) (found 1 results, but was looking for 2). Couldn't find Developer with id -9999."
1015
+ assert_equal(msg, e.message)
891
1016
  end
892
1017
 
893
1018
  def test_collection_singular_ids_through_setter_raises_exception_when_invalid_ids_set
894
1019
  author = authors(:david)
895
1020
  ids = [categories(:general).name, "Unknown"]
896
1021
  e = assert_raises(ActiveRecord::RecordNotFound) { author.essay_category_ids = ids }
897
- assert_equal "Couldn't find all Categories with 'name': (General, Unknown) (found 1 results, but was looking for 2)", e.message
1022
+ msg = "Couldn't find all Categories with 'name': (General, Unknown) (found 1 results, but was looking for 2). Couldn't find Category with name Unknown."
1023
+ assert_equal msg, e.message
898
1024
  end
899
1025
 
900
1026
  def test_build_a_model_from_hm_through_association_with_where_clause
901
- assert_nothing_raised { books(:awdr).subscribers.where(:nick => "marklazz").build }
1027
+ assert_nothing_raised { books(:awdr).subscribers.where(nick: "marklazz").build }
902
1028
  end
903
1029
 
904
1030
  def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_where_clause
905
- new_subscriber = books(:awdr).subscribers.where(:nick => "marklazz").build
1031
+ new_subscriber = books(:awdr).subscribers.where(nick: "marklazz").build
906
1032
  assert_equal new_subscriber.nick, "marklazz"
907
1033
  end
908
1034
 
909
1035
  def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_multiple_where_clauses
910
- new_subscriber = books(:awdr).subscribers.where(:nick => "marklazz").where(:name => 'Marcelo Giorgi').build
1036
+ new_subscriber = books(:awdr).subscribers.where(nick: "marklazz").where(name: "Marcelo Giorgi").build
911
1037
  assert_equal new_subscriber.nick, "marklazz"
912
1038
  assert_equal new_subscriber.name, "Marcelo Giorgi"
913
1039
  end
@@ -916,19 +1042,19 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
916
1042
  person = Person.new
917
1043
  reference = person.references.build
918
1044
  job = reference.build_job
919
- assert person.jobs.include?(job)
1045
+ assert_includes person.jobs, job
920
1046
  end
921
1047
 
922
1048
  def test_include_method_in_association_through_should_return_true_for_instance_added_with_nested_builds
923
1049
  author = Author.new
924
1050
  post = author.posts.build
925
1051
  comment = post.comments.build
926
- assert author.comments.include?(comment)
1052
+ assert_includes author.comments, comment
927
1053
  end
928
1054
 
929
1055
  def test_through_association_readonly_should_be_false
930
- assert !people(:michael).posts.first.readonly?
931
- assert !people(:michael).posts.to_a.first.readonly?
1056
+ assert_not_predicate people(:michael).posts.first, :readonly?
1057
+ assert_not_predicate people(:michael).posts.to_a.first, :readonly?
932
1058
  end
933
1059
 
934
1060
  def test_can_update_through_association
@@ -937,10 +1063,50 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
937
1063
  end
938
1064
  end
939
1065
 
1066
+ def test_has_many_through_with_source_scope
1067
+ expected = [readers(:michael_welcome).becomes(LazyReader)]
1068
+ assert_equal expected, Author.first.lazy_readers_skimmers_or_not
1069
+ assert_equal expected, Author.preload(:lazy_readers_skimmers_or_not).first.lazy_readers_skimmers_or_not
1070
+ assert_equal expected, Author.eager_load(:lazy_readers_skimmers_or_not).first.lazy_readers_skimmers_or_not
1071
+ end
1072
+
1073
+ def test_has_many_through_with_through_scope_with_includes
1074
+ expected = [readers(:bob_welcome).becomes(LazyReader)]
1075
+ assert_equal expected, Author.last.lazy_readers_skimmers_or_not_2
1076
+ assert_equal expected, Author.preload(:lazy_readers_skimmers_or_not_2).last.lazy_readers_skimmers_or_not_2
1077
+ assert_equal expected, Author.eager_load(:lazy_readers_skimmers_or_not_2).last.lazy_readers_skimmers_or_not_2
1078
+ end
1079
+
1080
+ def test_has_many_through_with_through_scope_with_joins
1081
+ expected = [readers(:bob_welcome).becomes(LazyReader)]
1082
+ assert_equal expected, Author.last.lazy_readers_skimmers_or_not_3
1083
+ assert_equal expected, Author.preload(:lazy_readers_skimmers_or_not_3).last.lazy_readers_skimmers_or_not_3
1084
+ assert_equal expected, Author.eager_load(:lazy_readers_skimmers_or_not_3).last.lazy_readers_skimmers_or_not_3
1085
+ end
1086
+
1087
+ def test_duplicated_has_many_through_with_through_scope_with_joins
1088
+ Categorization.create!(author: authors(:david), post: posts(:thinking), category: categories(:technology))
1089
+
1090
+ expected = [categorizations(:david_welcome_general)]
1091
+ assert_equal expected, Author.preload(:general_posts, :general_categorizations).first.general_categorizations
1092
+ assert_equal expected, Author.eager_load(:general_posts, :general_categorizations).first.general_categorizations
1093
+
1094
+ expected = [posts(:welcome)]
1095
+ assert_equal expected, Author.preload(:general_categorizations, :general_posts).first.general_posts
1096
+ assert_equal expected, Author.eager_load(:general_categorizations, :general_posts).first.general_posts
1097
+ end
1098
+
1099
+ def test_has_many_through_polymorphic_with_rewhere
1100
+ post = TaggedPost.create!(title: "Tagged", body: "Post")
1101
+ tag = post.tags.create!(name: "Tag")
1102
+ assert_equal [tag], TaggedPost.preload(:tags).last.tags
1103
+ assert_equal [tag], TaggedPost.eager_load(:tags).last.tags
1104
+ end
1105
+
940
1106
  def test_has_many_through_polymorphic_with_primary_key_option
941
1107
  assert_equal [categories(:general)], authors(:david).essay_categories
942
1108
 
943
- authors = Author.joins(:essay_categories).where('categories.id' => categories(:general).id)
1109
+ authors = Author.joins(:essay_categories).where("categories.id" => categories(:general).id)
944
1110
  assert_equal authors(:david), authors.first
945
1111
 
946
1112
  assert_equal [owners(:blackbeard)], authors(:david).essay_owners
@@ -952,7 +1118,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
952
1118
  def test_has_many_through_with_primary_key_option
953
1119
  assert_equal [categories(:general)], authors(:david).essay_categories_2
954
1120
 
955
- authors = Author.joins(:essay_categories_2).where('categories.id' => categories(:general).id)
1121
+ authors = Author.joins(:essay_categories_2).where("categories.id" => categories(:general).id)
956
1122
  assert_equal authors(:david), authors.first
957
1123
  end
958
1124
 
@@ -964,30 +1130,30 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
964
1130
  end
965
1131
 
966
1132
  def test_has_many_through_with_default_scope_on_join_model
967
- assert_equal posts(:welcome).comments.order('id').to_a, authors(:david).comments_on_first_posts
1133
+ assert_equal posts(:welcome).comments.order("id").to_a, authors(:david).comments_on_first_posts
968
1134
  end
969
1135
 
970
1136
  def test_create_has_many_through_with_default_scope_on_join_model
971
- category = authors(:david).special_categories.create(:name => "Foo")
972
- assert_equal 1, category.categorizations.where(:special => true).count
1137
+ category = authors(:david).special_categories.create(name: "Foo")
1138
+ assert_equal 1, category.categorizations.where(special: true).count
973
1139
  end
974
1140
 
975
1141
  def test_joining_has_many_through_with_distinct
976
- mary = Author.joins(:unique_categorized_posts).where(:id => authors(:mary).id).first
1142
+ mary = Author.joins(:unique_categorized_posts).where(id: authors(:mary).id).first
977
1143
  assert_equal 1, mary.unique_categorized_posts.length
978
1144
  assert_equal 1, mary.unique_categorized_post_ids.length
979
1145
  end
980
1146
 
981
1147
  def test_joining_has_many_through_belongs_to
982
- posts = Post.joins(:author_categorizations).order('posts.id').
983
- where('categorizations.id' => categorizations(:mary_thinking_sti).id)
1148
+ posts = Post.joins(:author_categorizations).order("posts.id").
1149
+ where("categorizations.id" => categorizations(:mary_thinking_sti).id)
984
1150
 
985
1151
  assert_equal [posts(:eager_other), posts(:misc_by_mary), posts(:other_by_mary)], posts
986
1152
  end
987
1153
 
988
1154
  def test_select_chosen_fields_only
989
1155
  author = authors(:david)
990
- assert_equal ['body', 'id'].sort, author.comments.select('comments.body').first.attributes.keys.sort
1156
+ assert_equal ["body", "id"].sort, author.comments.select("comments.body").first.attributes.keys.sort
991
1157
  end
992
1158
 
993
1159
  def test_get_has_many_through_belongs_to_ids_with_conditions
@@ -1010,12 +1176,12 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
1010
1176
  post.author_categorizations
1011
1177
  proxy = post.send(:association_instance_get, :author_categorizations)
1012
1178
 
1013
- assert !proxy.stale_target?
1179
+ assert_not_predicate proxy, :stale_target?
1014
1180
  assert_equal authors(:mary).categorizations.sort_by(&:id), post.author_categorizations.sort_by(&:id)
1015
1181
 
1016
1182
  post.author_id = authors(:david).id
1017
1183
 
1018
- assert proxy.stale_target?
1184
+ assert_predicate proxy, :stale_target?
1019
1185
  assert_equal authors(:david).categorizations.sort_by(&:id), post.author_categorizations.sort_by(&:id)
1020
1186
  end
1021
1187
 
@@ -1030,15 +1196,15 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
1030
1196
  post = posts(:welcome)
1031
1197
  address = author_addresses(:david_address)
1032
1198
 
1033
- assert post.author_addresses.include?(address)
1199
+ assert_includes post.author_addresses, address
1034
1200
  post.author_addresses.delete(address)
1035
- assert post[:author_count].nil?
1201
+ assert_predicate post[:author_count], :nil?
1036
1202
  end
1037
1203
 
1038
1204
  def test_primary_key_option_on_source
1039
1205
  post = posts(:welcome)
1040
1206
  category = categories(:general)
1041
- Categorization.create!(:post_id => post.id, :named_category_name => category.name)
1207
+ Categorization.create!(post_id: post.id, named_category_name: category.name)
1042
1208
 
1043
1209
  assert_equal [category], post.named_categories
1044
1210
  assert_equal [category.name], post.named_category_ids # checks when target loaded
@@ -1047,48 +1213,48 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
1047
1213
 
1048
1214
  def test_create_should_not_raise_exception_when_join_record_has_errors
1049
1215
  repair_validations(Categorization) do
1050
- Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
1051
- Category.create(:name => 'Fishing', :authors => [Author.first])
1216
+ Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
1217
+ assert_deprecated { Category.create(name: "Fishing", authors: [Author.first]) }
1052
1218
  end
1053
1219
  end
1054
1220
 
1055
1221
  def test_assign_array_to_new_record_builds_join_records
1056
- c = Category.new(:name => 'Fishing', :authors => [Author.first])
1222
+ c = Category.new(name: "Fishing", authors: [Author.first])
1057
1223
  assert_equal 1, c.categorizations.size
1058
1224
  end
1059
1225
 
1060
1226
  def test_create_bang_should_raise_exception_when_join_record_has_errors
1061
1227
  repair_validations(Categorization) do
1062
- Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
1228
+ Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
1063
1229
  assert_raises(ActiveRecord::RecordInvalid) do
1064
- Category.create!(:name => 'Fishing', :authors => [Author.first])
1230
+ assert_deprecated { Category.create!(name: "Fishing", authors: [Author.first]) }
1065
1231
  end
1066
1232
  end
1067
1233
  end
1068
1234
 
1069
1235
  def test_save_bang_should_raise_exception_when_join_record_has_errors
1070
1236
  repair_validations(Categorization) do
1071
- Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
1072
- c = Category.new(:name => 'Fishing', :authors => [Author.first])
1237
+ Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
1238
+ c = Category.new(name: "Fishing", authors: [Author.first])
1073
1239
  assert_raises(ActiveRecord::RecordInvalid) do
1074
- c.save!
1240
+ assert_deprecated { c.save! }
1075
1241
  end
1076
1242
  end
1077
1243
  end
1078
1244
 
1079
1245
  def test_save_returns_falsy_when_join_record_has_errors
1080
1246
  repair_validations(Categorization) do
1081
- Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
1082
- c = Category.new(:name => 'Fishing', :authors => [Author.first])
1083
- assert_not c.save
1247
+ Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
1248
+ c = Category.new(name: "Fishing", authors: [Author.first])
1249
+ assert_deprecated { assert_not c.save }
1084
1250
  end
1085
1251
  end
1086
1252
 
1087
1253
  def test_preloading_empty_through_association_via_joins
1088
- person = Person.create!(:first_name => "Gaga")
1089
- person = Person.where(:id => person.id).where('readers.id = 1 or 1=1').references(:readers).includes(:posts).to_a.first
1254
+ person = Person.create!(first_name: "Gaga")
1255
+ person = Person.where(id: person.id).where("readers.id = 1 or 1=1").references(:readers).includes(:posts).to_a.first
1090
1256
 
1091
- assert person.posts.loaded?, 'person.posts should be loaded'
1257
+ assert person.posts.loaded?, "person.posts should be loaded"
1092
1258
  assert_equal [], person.posts
1093
1259
  end
1094
1260
 
@@ -1109,13 +1275,13 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
1109
1275
  end
1110
1276
 
1111
1277
  def test_has_many_through_with_polymorphic_source
1112
- post = tags(:general).tagged_posts.create! :title => "foo", :body => "bar"
1278
+ post = tags(:general).tagged_posts.create! title: "foo", body: "bar"
1113
1279
  assert_equal [tags(:general)], post.reload.tags
1114
1280
  end
1115
1281
 
1116
1282
  def test_has_many_through_obeys_order_on_through_association
1117
1283
  owner = owners(:blackbeard)
1118
- assert owner.toys.to_sql.include?("pets.name desc")
1284
+ assert_includes owner.toys.to_sql, "pets.name desc"
1119
1285
  assert_equal ["parrot", "bulbul"], owner.toys.map { |r| r.pet.name }
1120
1286
  end
1121
1287
 
@@ -1148,9 +1314,9 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
1148
1314
  def test_has_many_through_associations_on_new_records_use_null_relations
1149
1315
  person = Person.new
1150
1316
 
1151
- assert_no_queries(ignore_none: false) do
1317
+ assert_no_queries do
1152
1318
  assert_equal [], person.posts
1153
- assert_equal [], person.posts.where(body: 'omg')
1319
+ assert_equal [], person.posts.where(body: "omg")
1154
1320
  assert_equal [], person.posts.pluck(:body)
1155
1321
  assert_equal 0, person.posts.sum(:tags_count)
1156
1322
  assert_equal 0, person.posts.count
@@ -1182,9 +1348,9 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
1182
1348
  end
1183
1349
 
1184
1350
  def test_has_many_through_unscope_default_scope
1185
- post = Post.create!(:title => 'Beaches', :body => "I like beaches!")
1186
- Reader.create! :person => people(:david), :post => post
1187
- LazyReader.create! :person => people(:susan), :post => post
1351
+ post = Post.create!(title: "Beaches", body: "I like beaches!")
1352
+ Reader.create! person: people(:david), post: post
1353
+ LazyReader.create! person: people(:susan), post: post
1188
1354
 
1189
1355
  assert_equal 2, post.people.to_a.size
1190
1356
  assert_equal 1, post.lazy_people.to_a.size
@@ -1194,8 +1360,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
1194
1360
  end
1195
1361
 
1196
1362
  def test_has_many_through_add_with_sti_middle_relation
1197
- club = SuperClub.create!(name: 'Fight Club')
1198
- member = Member.create!(name: 'Tyler Durden')
1363
+ club = SuperClub.create!(name: "Fight Club")
1364
+ member = Member.create!(name: "Tyler Durden")
1199
1365
 
1200
1366
  club.members << member
1201
1367
  assert_equal 1, SuperMembership.where(member_id: member.id, club_id: club.id).count
@@ -1216,12 +1382,6 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
1216
1382
  assert_nil Club.new.special_favourites.distinct_value
1217
1383
  end
1218
1384
 
1219
- def test_association_force_reload_with_only_true_is_deprecated
1220
- post = Post.find(1)
1221
-
1222
- assert_deprecated { post.people(true) }
1223
- end
1224
-
1225
1385
  def test_has_many_through_do_not_cache_association_reader_if_the_though_method_has_default_scopes
1226
1386
  member = Member.create!
1227
1387
  club = Club.create!
@@ -1250,6 +1410,33 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
1250
1410
  TenantMembership.current_member = nil
1251
1411
  end
1252
1412
 
1413
+ def test_has_many_through_with_scope_that_has_joined_same_table_with_parent_relation
1414
+ assert_equal authors(:david), Author.joins(:comments_for_first_author).take
1415
+ end
1416
+
1417
+ def test_has_many_through_with_left_joined_same_table_with_through_table
1418
+ assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.left_joins(:post)
1419
+ end
1420
+
1421
+ def test_has_many_through_with_unscope_should_affect_to_through_scope
1422
+ assert_equal [comments(:eager_other_comment1)], authors(:mary).unordered_comments
1423
+ end
1424
+
1425
+ def test_has_many_through_with_scope_should_accept_string_and_hash_join
1426
+ assert_equal authors(:david), Author.joins({ comments_for_first_author: :post }, "inner join posts posts_alias on authors.id = posts_alias.author_id").eager_load(:categories).take
1427
+ end
1428
+
1429
+ def test_has_many_through_with_scope_should_respect_table_alias
1430
+ family = Family.create!
1431
+ users = 3.times.map { User.create! }
1432
+ FamilyTree.create!(member: users[0], family: family)
1433
+ FamilyTree.create!(member: users[1], family: family)
1434
+ FamilyTree.create!(member: users[2], family: family, token: "wat")
1435
+
1436
+ assert_equal 2, users[0].family_members.to_a.size
1437
+ assert_equal 0, users[2].family_members.to_a.size
1438
+ end
1439
+
1253
1440
  def test_through_scope_is_affected_by_unscoping
1254
1441
  author = authors(:david)
1255
1442
 
@@ -1268,4 +1455,126 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
1268
1455
  assert_equal expected.sort_by(&:id), author.comments_on_first_posts.sort_by(&:id)
1269
1456
  end
1270
1457
  end
1458
+
1459
+ def test_incorrectly_ordered_through_associations
1460
+ assert_raises(ActiveRecord::HasManyThroughOrderError) do
1461
+ DeveloperWithIncorrectlyOrderedHasManyThrough.create(
1462
+ companies: [Company.create]
1463
+ )
1464
+ end
1465
+ end
1466
+
1467
+ def test_has_many_through_update_ids_with_conditions
1468
+ author = Author.create!(name: "Bill")
1469
+ category = categories(:general)
1470
+
1471
+ author.update(
1472
+ special_categories_with_condition_ids: [category.id],
1473
+ nonspecial_categories_with_condition_ids: [category.id]
1474
+ )
1475
+
1476
+ assert_equal [category.id], author.special_categories_with_condition_ids
1477
+ assert_equal [category.id], author.nonspecial_categories_with_condition_ids
1478
+
1479
+ author.update(nonspecial_categories_with_condition_ids: [])
1480
+ author.reload
1481
+
1482
+ assert_equal [category.id], author.special_categories_with_condition_ids
1483
+ assert_equal [], author.nonspecial_categories_with_condition_ids
1484
+ end
1485
+
1486
+ def test_single_has_many_through_association_with_unpersisted_parent_instance
1487
+ post_with_single_has_many_through = Class.new(Post) do
1488
+ def self.name; "PostWithSingleHasManyThrough"; end
1489
+ has_many :subscriptions, through: :author
1490
+ end
1491
+ post = post_with_single_has_many_through.new
1492
+
1493
+ post.author = authors(:mary)
1494
+ book1 = Book.create!(name: "essays on single has many through associations 1")
1495
+ post.author.books << book1
1496
+ subscription1 = Subscription.first
1497
+ book1.subscriptions << subscription1
1498
+ assert_equal [subscription1], post.subscriptions.to_a
1499
+
1500
+ post.author = authors(:bob)
1501
+ book2 = Book.create!(name: "essays on single has many through associations 2")
1502
+ post.author.books << book2
1503
+ subscription2 = Subscription.second
1504
+ book2.subscriptions << subscription2
1505
+ assert_equal [subscription2], post.subscriptions.to_a
1506
+ end
1507
+
1508
+ def test_nested_has_many_through_association_with_unpersisted_parent_instance
1509
+ post_with_nested_has_many_through = Class.new(Post) do
1510
+ def self.name; "PostWithNestedHasManyThrough"; end
1511
+ has_many :books, through: :author
1512
+ has_many :subscriptions, through: :books
1513
+ end
1514
+ post = post_with_nested_has_many_through.new
1515
+
1516
+ post.author = authors(:mary)
1517
+ book1 = Book.create!(name: "essays on nested has many through associations 1")
1518
+ post.author.books << book1
1519
+ subscription1 = Subscription.first
1520
+ book1.subscriptions << subscription1
1521
+ assert_equal [subscription1], post.subscriptions.to_a
1522
+
1523
+ post.author = authors(:bob)
1524
+ book2 = Book.create!(name: "essays on nested has many through associations 2")
1525
+ post.author.books << book2
1526
+ subscription2 = Subscription.second
1527
+ book2.subscriptions << subscription2
1528
+ assert_equal [subscription2], post.subscriptions.to_a
1529
+ end
1530
+
1531
+ def test_child_is_visible_to_join_model_in_add_association_callbacks
1532
+ [:before_add, :after_add].each do |callback_name|
1533
+ sentient_treasure = Class.new(Treasure) do
1534
+ def self.name; "SentientTreasure"; end
1535
+
1536
+ has_many :pet_treasures, foreign_key: :treasure_id, callback_name => :check_pet!
1537
+ has_many :pets, through: :pet_treasures
1538
+
1539
+ def check_pet!(added)
1540
+ raise "No pet!" if added.pet.nil?
1541
+ end
1542
+ end
1543
+
1544
+ treasure = sentient_treasure.new
1545
+ assert_nothing_raised { treasure.pets << pets(:mochi) }
1546
+ end
1547
+ end
1548
+
1549
+ def test_circular_autosave_association_correctly_saves_multiple_records
1550
+ cs180 = Seminar.new(name: "CS180")
1551
+ fall = Session.new(name: "Fall")
1552
+ sections = [
1553
+ cs180.sections.build(short_name: "A"),
1554
+ cs180.sections.build(short_name: "B"),
1555
+ ]
1556
+ fall.sections << sections
1557
+ fall.save!
1558
+ fall.reload
1559
+ assert_equal sections, fall.sections.sort_by(&:id)
1560
+ end
1561
+
1562
+ private
1563
+ def make_model(name)
1564
+ Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } }
1565
+ end
1566
+
1567
+ def make_no_pk_hm_t
1568
+ lesson = make_model "Lesson"
1569
+ student = make_model "Student"
1570
+
1571
+ lesson_student = make_model "LessonStudent"
1572
+ lesson_student.table_name = "lessons_students"
1573
+
1574
+ lesson_student.belongs_to :lesson, anonymous_class: lesson
1575
+ lesson_student.belongs_to :student, anonymous_class: student
1576
+ lesson.has_many :lesson_students, anonymous_class: lesson_student
1577
+ lesson.has_many :students, through: :lesson_students, anonymous_class: student
1578
+ [lesson, lesson_student, student]
1579
+ end
1271
1580
  end