ibm_db 3.0.4 → 5.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (351) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +8 -1
  3. data/LICENSE +1 -1
  4. data/ParameterizedQueries README +6 -6
  5. data/README +38 -55
  6. data/ext/Makefile +266 -0
  7. data/ext/extconf.rb +34 -3
  8. data/ext/gil_release_version +3 -0
  9. data/ext/ibm_db.c +106 -111
  10. data/ext/ibm_db.o +0 -0
  11. data/ext/ibm_db.so +0 -0
  12. data/ext/mkmf.log +103 -0
  13. data/ext/ruby_ibm_db_cli.o +0 -0
  14. data/ext/unicode_support_version +3 -0
  15. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +911 -527
  16. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +4 -1
  17. data/test/active_record/connection_adapters/fake_adapter.rb +8 -5
  18. data/test/cases/adapter_test.rb +148 -58
  19. data/test/cases/adapters/mysql2/active_schema_test.rb +193 -0
  20. data/test/cases/adapters/mysql2/bind_parameter_test.rb +50 -0
  21. data/test/cases/adapters/mysql2/boolean_test.rb +100 -0
  22. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +63 -0
  23. data/test/cases/adapters/mysql2/charset_collation_test.rb +54 -0
  24. data/test/cases/adapters/mysql2/connection_test.rb +210 -0
  25. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +45 -0
  26. data/test/cases/adapters/mysql2/enum_test.rb +26 -0
  27. data/test/cases/adapters/mysql2/explain_test.rb +21 -0
  28. data/test/cases/adapters/mysql2/json_test.rb +195 -0
  29. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +83 -0
  30. data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -0
  31. data/test/cases/adapters/mysql2/schema_migrations_test.rb +59 -0
  32. data/test/cases/adapters/mysql2/schema_test.rb +126 -0
  33. data/test/cases/adapters/mysql2/sp_test.rb +36 -0
  34. data/test/cases/adapters/mysql2/sql_types_test.rb +14 -0
  35. data/test/cases/adapters/mysql2/table_options_test.rb +42 -0
  36. data/test/cases/adapters/mysql2/unsigned_type_test.rb +66 -0
  37. data/test/cases/adapters/postgresql/active_schema_test.rb +98 -0
  38. data/test/cases/adapters/postgresql/array_test.rb +339 -0
  39. data/test/cases/adapters/postgresql/bit_string_test.rb +82 -0
  40. data/test/cases/adapters/postgresql/bytea_test.rb +134 -0
  41. data/test/cases/adapters/postgresql/case_insensitive_test.rb +26 -0
  42. data/test/cases/adapters/postgresql/change_schema_test.rb +38 -0
  43. data/test/cases/adapters/postgresql/cidr_test.rb +25 -0
  44. data/test/cases/adapters/postgresql/citext_test.rb +78 -0
  45. data/test/cases/adapters/postgresql/collation_test.rb +53 -0
  46. data/test/cases/adapters/postgresql/composite_test.rb +132 -0
  47. data/test/cases/adapters/postgresql/connection_test.rb +257 -0
  48. data/test/cases/adapters/postgresql/datatype_test.rb +92 -0
  49. data/test/cases/adapters/postgresql/domain_test.rb +47 -0
  50. data/test/cases/adapters/postgresql/enum_test.rb +91 -0
  51. data/test/cases/adapters/postgresql/explain_test.rb +20 -0
  52. data/test/cases/adapters/postgresql/extension_migration_test.rb +63 -0
  53. data/test/cases/adapters/postgresql/full_text_test.rb +44 -0
  54. data/test/cases/adapters/postgresql/geometric_test.rb +378 -0
  55. data/test/cases/adapters/postgresql/hstore_test.rb +382 -0
  56. data/test/cases/adapters/postgresql/infinity_test.rb +69 -0
  57. data/test/cases/adapters/postgresql/integer_test.rb +25 -0
  58. data/test/cases/adapters/postgresql/json_test.rb +237 -0
  59. data/test/cases/adapters/postgresql/ltree_test.rb +53 -0
  60. data/test/cases/adapters/postgresql/money_test.rb +96 -0
  61. data/test/cases/adapters/postgresql/network_test.rb +94 -0
  62. data/test/cases/adapters/postgresql/numbers_test.rb +49 -0
  63. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +405 -0
  64. data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -0
  65. data/test/cases/adapters/postgresql/quoting_test.rb +44 -0
  66. data/test/cases/adapters/postgresql/range_test.rb +343 -0
  67. data/test/cases/adapters/postgresql/referential_integrity_test.rb +111 -0
  68. data/test/cases/adapters/postgresql/rename_table_test.rb +34 -0
  69. data/test/cases/adapters/postgresql/schema_authorization_test.rb +119 -0
  70. data/test/cases/adapters/postgresql/schema_test.rb +597 -0
  71. data/test/cases/adapters/postgresql/serial_test.rb +154 -0
  72. data/test/cases/adapters/postgresql/statement_pool_test.rb +41 -0
  73. data/test/cases/adapters/postgresql/timestamp_test.rb +90 -0
  74. data/test/cases/adapters/postgresql/type_lookup_test.rb +33 -0
  75. data/test/cases/adapters/postgresql/utils_test.rb +62 -0
  76. data/test/cases/adapters/postgresql/uuid_test.rb +294 -0
  77. data/test/cases/adapters/postgresql/xml_test.rb +54 -0
  78. data/test/cases/adapters/sqlite3/collation_test.rb +53 -0
  79. data/test/cases/adapters/sqlite3/copy_table_test.rb +98 -0
  80. data/test/cases/adapters/sqlite3/explain_test.rb +21 -0
  81. data/test/cases/adapters/sqlite3/quoting_test.rb +101 -0
  82. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +441 -0
  83. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -0
  84. data/test/cases/adapters/sqlite3/statement_pool_test.rb +20 -0
  85. data/test/cases/aggregations_test.rb +11 -1
  86. data/test/cases/ar_schema_test.rb +35 -50
  87. data/test/cases/associations/association_scope_test.rb +1 -6
  88. data/test/cases/associations/belongs_to_associations_test.rb +122 -10
  89. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +41 -0
  90. data/test/cases/associations/callbacks_test.rb +5 -7
  91. data/test/cases/associations/cascaded_eager_loading_test.rb +1 -1
  92. data/test/cases/associations/eager_load_nested_include_test.rb +1 -3
  93. data/test/cases/associations/eager_test.rb +176 -73
  94. data/test/cases/associations/extension_test.rb +7 -2
  95. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +104 -32
  96. data/test/cases/associations/has_many_associations_test.rb +382 -43
  97. data/test/cases/associations/has_many_through_associations_test.rb +108 -41
  98. data/test/cases/associations/has_one_associations_test.rb +105 -8
  99. data/test/cases/associations/has_one_through_associations_test.rb +6 -3
  100. data/test/cases/associations/inner_join_association_test.rb +3 -3
  101. data/test/cases/associations/inverse_associations_test.rb +51 -11
  102. data/test/cases/associations/join_model_test.rb +59 -36
  103. data/test/cases/associations/left_outer_join_association_test.rb +88 -0
  104. data/test/cases/associations/nested_through_associations_test.rb +2 -2
  105. data/test/cases/associations/required_test.rb +25 -5
  106. data/test/cases/associations_test.rb +39 -34
  107. data/test/cases/attribute_decorators_test.rb +9 -8
  108. data/test/cases/attribute_methods/read_test.rb +5 -5
  109. data/test/cases/attribute_methods_test.rb +97 -40
  110. data/test/cases/attribute_set_test.rb +74 -4
  111. data/test/cases/attribute_test.rb +84 -18
  112. data/test/cases/attributes_test.rb +151 -34
  113. data/test/cases/autosave_association_test.rb +149 -36
  114. data/test/cases/base_test.rb +311 -236
  115. data/test/cases/batches_test.rb +299 -22
  116. data/test/cases/binary_test.rb +2 -10
  117. data/test/cases/bind_parameter_test.rb +76 -66
  118. data/test/cases/cache_key_test.rb +26 -0
  119. data/test/cases/calculations_test.rb +167 -15
  120. data/test/cases/callbacks_test.rb +161 -68
  121. data/test/cases/coders/json_test.rb +15 -0
  122. data/test/cases/collection_cache_key_test.rb +115 -0
  123. data/test/cases/column_definition_test.rb +26 -57
  124. data/test/cases/comment_test.rb +145 -0
  125. data/test/cases/connection_adapters/adapter_leasing_test.rb +5 -3
  126. data/test/cases/connection_adapters/connection_handler_test.rb +128 -21
  127. data/test/cases/connection_adapters/connection_specification_test.rb +1 -1
  128. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +0 -38
  129. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +5 -1
  130. data/test/cases/connection_adapters/schema_cache_test.rb +8 -3
  131. data/test/cases/connection_adapters/type_lookup_test.rb +15 -7
  132. data/test/cases/connection_management_test.rb +46 -56
  133. data/test/cases/connection_pool_test.rb +195 -20
  134. data/test/cases/connection_specification/resolver_test.rb +15 -0
  135. data/test/cases/counter_cache_test.rb +10 -5
  136. data/test/cases/custom_locking_test.rb +1 -1
  137. data/test/cases/database_statements_test.rb +18 -3
  138. data/test/cases/{invalid_date_test.rb → date_test.rb} +13 -1
  139. data/test/cases/date_time_precision_test.rb +107 -0
  140. data/test/cases/defaults_test.rb +85 -89
  141. data/test/cases/dirty_test.rb +32 -44
  142. data/test/cases/disconnected_test.rb +4 -2
  143. data/test/cases/enum_test.rb +178 -24
  144. data/test/cases/errors_test.rb +16 -0
  145. data/test/cases/explain_test.rb +32 -21
  146. data/test/cases/finder_test.rb +279 -151
  147. data/test/cases/fixture_set/file_test.rb +18 -0
  148. data/test/cases/fixtures_test.rb +123 -32
  149. data/test/cases/forbidden_attributes_protection_test.rb +69 -3
  150. data/test/cases/helper.rb +10 -16
  151. data/test/cases/hot_compatibility_test.rb +89 -1
  152. data/test/cases/inheritance_test.rb +284 -53
  153. data/test/cases/integration_test.rb +23 -7
  154. data/test/cases/invalid_connection_test.rb +4 -2
  155. data/test/cases/invertible_migration_test.rb +124 -32
  156. data/test/cases/json_serialization_test.rb +11 -2
  157. data/test/cases/locking_test.rb +22 -6
  158. data/test/cases/log_subscriber_test.rb +106 -17
  159. data/test/cases/migration/change_schema_test.rb +118 -132
  160. data/test/cases/migration/change_table_test.rb +34 -2
  161. data/test/cases/migration/column_attributes_test.rb +7 -23
  162. data/test/cases/migration/column_positioning_test.rb +8 -8
  163. data/test/cases/migration/columns_test.rb +17 -11
  164. data/test/cases/migration/command_recorder_test.rb +47 -2
  165. data/test/cases/migration/compatibility_test.rb +118 -0
  166. data/test/cases/migration/create_join_table_test.rb +21 -12
  167. data/test/cases/migration/foreign_key_test.rb +68 -66
  168. data/test/cases/migration/index_test.rb +14 -12
  169. data/test/cases/migration/logger_test.rb +1 -1
  170. data/test/cases/migration/pending_migrations_test.rb +0 -1
  171. data/test/cases/migration/references_foreign_key_test.rb +114 -107
  172. data/test/cases/migration/references_index_test.rb +4 -4
  173. data/test/cases/migration/references_statements_test.rb +26 -6
  174. data/test/cases/migration/rename_table_test.rb +25 -25
  175. data/test/cases/migration_test.rb +279 -81
  176. data/test/cases/migrator_test.rb +91 -8
  177. data/test/cases/mixin_test.rb +0 -2
  178. data/test/cases/modules_test.rb +3 -4
  179. data/test/cases/multiparameter_attributes_test.rb +24 -2
  180. data/test/cases/multiple_db_test.rb +18 -11
  181. data/test/cases/nested_attributes_test.rb +74 -33
  182. data/test/cases/persistence_test.rb +102 -10
  183. data/test/cases/pooled_connections_test.rb +3 -3
  184. data/test/cases/primary_keys_test.rb +170 -31
  185. data/test/cases/query_cache_test.rb +216 -96
  186. data/test/cases/quoting_test.rb +65 -19
  187. data/test/cases/readonly_test.rb +2 -1
  188. data/test/cases/reflection_test.rb +77 -22
  189. data/test/cases/relation/delegation_test.rb +3 -8
  190. data/test/cases/relation/merging_test.rb +10 -14
  191. data/test/cases/relation/mutation_test.rb +42 -24
  192. data/test/cases/relation/or_test.rb +92 -0
  193. data/test/cases/relation/predicate_builder_test.rb +4 -2
  194. data/test/cases/relation/record_fetch_warning_test.rb +40 -0
  195. data/test/cases/relation/where_chain_test.rb +23 -99
  196. data/test/cases/relation/where_clause_test.rb +182 -0
  197. data/test/cases/relation/where_test.rb +45 -23
  198. data/test/cases/relation_test.rb +89 -58
  199. data/test/cases/relations_test.rb +249 -38
  200. data/test/cases/result_test.rb +10 -0
  201. data/test/cases/sanitize_test.rb +108 -15
  202. data/test/cases/schema_dumper_test.rb +119 -125
  203. data/test/cases/schema_loading_test.rb +52 -0
  204. data/test/cases/scoping/default_scoping_test.rb +113 -39
  205. data/test/cases/scoping/named_scoping_test.rb +46 -9
  206. data/test/cases/scoping/relation_scoping_test.rb +47 -4
  207. data/test/cases/secure_token_test.rb +32 -0
  208. data/test/cases/serialization_test.rb +1 -1
  209. data/test/cases/serialized_attribute_test.rb +93 -6
  210. data/test/cases/statement_cache_test.rb +38 -0
  211. data/test/cases/store_test.rb +2 -1
  212. data/test/cases/suppressor_test.rb +63 -0
  213. data/test/cases/tasks/database_tasks_test.rb +74 -8
  214. data/test/cases/tasks/mysql_rake_test.rb +143 -109
  215. data/test/cases/tasks/postgresql_rake_test.rb +71 -12
  216. data/test/cases/tasks/sqlite_rake_test.rb +30 -3
  217. data/test/cases/test_case.rb +28 -20
  218. data/test/cases/test_fixtures_test.rb +36 -0
  219. data/test/cases/time_precision_test.rb +103 -0
  220. data/test/cases/timestamp_test.rb +47 -14
  221. data/test/cases/touch_later_test.rb +121 -0
  222. data/test/cases/transaction_callbacks_test.rb +128 -62
  223. data/test/cases/transaction_isolation_test.rb +2 -2
  224. data/test/cases/transactions_test.rb +61 -43
  225. data/test/cases/type/adapter_specific_registry_test.rb +133 -0
  226. data/test/cases/type/date_time_test.rb +14 -0
  227. data/test/cases/type/integer_test.rb +2 -96
  228. data/test/cases/type/string_test.rb +0 -14
  229. data/test/cases/type_test.rb +39 -0
  230. data/test/cases/types_test.rb +1 -118
  231. data/test/cases/unconnected_test.rb +1 -1
  232. data/test/cases/validations/absence_validation_test.rb +73 -0
  233. data/test/cases/validations/association_validation_test.rb +13 -2
  234. data/test/cases/validations/i18n_validation_test.rb +6 -10
  235. data/test/cases/validations/length_validation_test.rb +62 -30
  236. data/test/cases/validations/presence_validation_test.rb +36 -1
  237. data/test/cases/validations/uniqueness_validation_test.rb +150 -36
  238. data/test/cases/validations_repair_helper.rb +2 -6
  239. data/test/cases/validations_test.rb +36 -7
  240. data/test/cases/view_test.rb +108 -5
  241. data/test/cases/yaml_serialization_test.rb +36 -1
  242. data/test/config.example.yml +97 -0
  243. data/test/fixtures/bad_posts.yml +9 -0
  244. data/test/fixtures/books.yml +20 -0
  245. data/test/fixtures/content.yml +3 -0
  246. data/test/fixtures/content_positions.yml +3 -0
  247. data/test/fixtures/dead_parrots.yml +5 -0
  248. data/test/fixtures/live_parrots.yml +4 -0
  249. data/test/fixtures/naked/yml/parrots.yml +2 -0
  250. data/test/fixtures/naked/yml/trees.yml +3 -0
  251. data/test/fixtures/nodes.yml +29 -0
  252. data/test/fixtures/other_comments.yml +6 -0
  253. data/test/fixtures/other_dogs.yml +2 -0
  254. data/test/fixtures/other_posts.yml +7 -0
  255. data/test/fixtures/price_estimates.yml +10 -1
  256. data/test/fixtures/trees.yml +3 -0
  257. data/test/migrations/10_urban/9_add_expressions.rb +1 -1
  258. data/test/migrations/decimal/1_give_me_big_numbers.rb +1 -1
  259. data/test/migrations/magic/1_currencies_have_symbols.rb +1 -1
  260. data/test/migrations/missing/1000_people_have_middle_names.rb +2 -2
  261. data/test/migrations/missing/1_people_have_last_names.rb +2 -2
  262. data/test/migrations/missing/3_we_need_reminders.rb +2 -2
  263. data/test/migrations/missing/4_innocent_jointable.rb +2 -2
  264. data/test/migrations/rename/1_we_need_things.rb +2 -2
  265. data/test/migrations/rename/2_rename_things.rb +2 -2
  266. data/test/migrations/to_copy/1_people_have_hobbies.rb +1 -1
  267. data/test/migrations/to_copy/2_people_have_descriptions.rb +1 -1
  268. data/test/migrations/to_copy2/1_create_articles.rb +1 -1
  269. data/test/migrations/to_copy2/2_create_comments.rb +1 -1
  270. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +1 -1
  271. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +1 -1
  272. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +1 -1
  273. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +1 -1
  274. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +1 -1
  275. data/test/migrations/valid/1_valid_people_have_last_names.rb +1 -1
  276. data/test/migrations/valid/2_we_need_reminders.rb +2 -2
  277. data/test/migrations/valid/3_innocent_jointable.rb +2 -2
  278. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +1 -1
  279. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +2 -2
  280. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +2 -2
  281. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +1 -1
  282. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +1 -1
  283. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +1 -1
  284. data/test/migrations/version_check/20131219224947_migration_version_check.rb +1 -1
  285. data/test/models/admin/randomly_named_c1.rb +6 -2
  286. data/test/models/aircraft.rb +1 -0
  287. data/test/models/author.rb +4 -7
  288. data/test/models/bird.rb +1 -1
  289. data/test/models/book.rb +5 -0
  290. data/test/models/bulb.rb +2 -1
  291. data/test/models/car.rb +3 -0
  292. data/test/models/cat.rb +10 -0
  293. data/test/models/chef.rb +5 -0
  294. data/test/models/club.rb +2 -0
  295. data/test/models/comment.rb +17 -5
  296. data/test/models/company.rb +7 -2
  297. data/test/models/company_in_module.rb +1 -1
  298. data/test/models/contact.rb +1 -1
  299. data/test/models/content.rb +40 -0
  300. data/test/models/customer.rb +8 -2
  301. data/test/models/developer.rb +22 -0
  302. data/test/models/face.rb +1 -1
  303. data/test/models/guitar.rb +4 -0
  304. data/test/models/hotel.rb +5 -0
  305. data/test/models/member.rb +1 -0
  306. data/test/models/member_detail.rb +4 -3
  307. data/test/models/mentor.rb +3 -0
  308. data/test/models/mocktail_designer.rb +2 -0
  309. data/test/models/node.rb +5 -0
  310. data/test/models/non_primary_key.rb +2 -0
  311. data/test/models/notification.rb +3 -0
  312. data/test/models/other_dog.rb +5 -0
  313. data/test/models/owner.rb +4 -1
  314. data/test/models/parrot.rb +6 -7
  315. data/test/models/person.rb +0 -1
  316. data/test/models/pet.rb +3 -0
  317. data/test/models/pet_treasure.rb +6 -0
  318. data/test/models/pirate.rb +3 -3
  319. data/test/models/post.rb +18 -9
  320. data/test/models/project.rb +11 -0
  321. data/test/models/randomly_named_c1.rb +1 -1
  322. data/test/models/recipe.rb +3 -0
  323. data/test/models/ship.rb +8 -2
  324. data/test/models/tag.rb +6 -0
  325. data/test/models/topic.rb +2 -8
  326. data/test/models/tree.rb +3 -0
  327. data/test/models/tuning_peg.rb +4 -0
  328. data/test/models/user.rb +14 -0
  329. data/test/models/uuid_item.rb +6 -0
  330. data/test/schema/mysql2_specific_schema.rb +33 -23
  331. data/test/schema/oracle_specific_schema.rb +1 -4
  332. data/test/schema/postgresql_specific_schema.rb +36 -124
  333. data/test/schema/schema.rb +183 -64
  334. data/test/schema/schema.rb.original +1057 -0
  335. data/test/schema/sqlite_specific_schema.rb +1 -5
  336. data/test/support/connection.rb +1 -0
  337. data/test/support/schema_dumping_helper.rb +1 -1
  338. data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -0
  339. data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -0
  340. metadata +145 -26
  341. data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +0 -26
  342. data/test/cases/attribute_methods/serialization_test.rb +0 -29
  343. data/test/cases/migration/change_schema_test - Copy.rb +0 -448
  344. data/test/cases/migration/foreign_key_test - Changed.rb +0 -325
  345. data/test/cases/migration/table_and_index_test.rb +0 -24
  346. data/test/cases/relation/where_test2.rb +0 -36
  347. data/test/cases/type/decimal_test.rb +0 -51
  348. data/test/cases/type/unsigned_integer_test.rb +0 -18
  349. data/test/cases/xml_serialization_test.rb +0 -457
  350. data/test/fixtures/naked/csv/accounts.csv +0 -1
  351. data/test/schema/mysql_specific_schema.rb +0 -70
@@ -73,10 +73,15 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase
73
73
  assert_equal post.association(:comments), post.comments.where('1=1').the_association
74
74
  end
75
75
 
76
+ def test_association_with_default_scope
77
+ assert_raises OopsError do
78
+ posts(:welcome).comments.destroy_all
79
+ end
80
+ end
81
+
76
82
  private
77
83
 
78
84
  def extend!(model)
79
- builder = ActiveRecord::Associations::Builder::HasMany.new(model, :association_name, nil, {}) { }
80
- builder.define_extensions(model)
85
+ ActiveRecord::Associations::Builder::HasMany.define_extensions(model, :association_name) { }
81
86
  end
82
87
  end
@@ -19,6 +19,7 @@ require 'models/professor'
19
19
  require 'models/treasure'
20
20
  require 'models/price_estimate'
21
21
  require 'models/club'
22
+ require 'models/user'
22
23
  require 'models/member'
23
24
  require 'models/membership'
24
25
  require 'models/sponsor'
@@ -95,6 +96,15 @@ class DeveloperWithExtendOption < Developer
95
96
  has_and_belongs_to_many :projects, extend: NamedExtension
96
97
  end
97
98
 
99
+ class ProjectUnscopingDavidDefaultScope < ActiveRecord::Base
100
+ self.table_name = 'projects'
101
+ has_and_belongs_to_many :developers, -> { unscope(where: 'name') },
102
+ class_name: "LazyBlockDeveloperCalledDavid",
103
+ join_table: "developers_projects",
104
+ foreign_key: "project_id",
105
+ association_foreign_key: "developer_id"
106
+ end
107
+
98
108
  class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
99
109
  fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
100
110
  :parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings, :computers
@@ -137,6 +147,19 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
137
147
  assert_equal 1, country.treaties.count
138
148
  end
139
149
 
150
+ def test_join_table_composite_primary_key_should_not_warn
151
+ country = Country.new(:name => 'India')
152
+ country.country_id = 'c1'
153
+ country.save!
154
+
155
+ treaty = Treaty.new(:name => 'peace')
156
+ treaty.treaty_id = 't1'
157
+ warning = capture(:stderr) do
158
+ country.treaties << treaty
159
+ end
160
+ assert_no_match(/WARNING: Active Record does not support composite primary key\./, warning)
161
+ end
162
+
140
163
  def test_has_and_belongs_to_many
141
164
  david = Developer.find(1)
142
165
 
@@ -159,8 +182,8 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
159
182
  jamis.projects << action_controller
160
183
 
161
184
  assert_equal 2, jamis.projects.size
162
- assert_equal 2, jamis.projects(true).size
163
- assert_equal 2, action_controller.developers(true).size
185
+ assert_equal 2, jamis.projects.reload.size
186
+ assert_equal 2, action_controller.developers.reload.size
164
187
  end
165
188
 
166
189
  def test_adding_type_mismatch
@@ -178,9 +201,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
178
201
 
179
202
  action_controller.developers << jamis
180
203
 
181
- assert_equal 2, jamis.projects(true).size
204
+ assert_equal 2, jamis.projects.reload.size
182
205
  assert_equal 2, action_controller.developers.size
183
- assert_equal 2, action_controller.developers(true).size
206
+ assert_equal 2, action_controller.developers.reload.size
184
207
  end
185
208
 
186
209
  def test_adding_from_the_project_fixed_timestamp
@@ -194,9 +217,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
194
217
  action_controller.developers << jamis
195
218
 
196
219
  assert_equal updated_at, jamis.updated_at
197
- assert_equal 2, jamis.projects(true).size
220
+ assert_equal 2, jamis.projects.reload.size
198
221
  assert_equal 2, action_controller.developers.size
199
- assert_equal 2, action_controller.developers(true).size
222
+ assert_equal 2, action_controller.developers.reload.size
200
223
  end
201
224
 
202
225
  def test_adding_multiple
@@ -205,7 +228,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
205
228
  aredridel.projects.reload
206
229
  aredridel.projects.push(Project.find(1), Project.find(2))
207
230
  assert_equal 2, aredridel.projects.size
208
- assert_equal 2, aredridel.projects(true).size
231
+ assert_equal 2, aredridel.projects.reload.size
209
232
  end
210
233
 
211
234
  def test_adding_a_collection
@@ -214,7 +237,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
214
237
  aredridel.projects.reload
215
238
  aredridel.projects.concat([Project.find(1), Project.find(2)])
216
239
  assert_equal 2, aredridel.projects.size
217
- assert_equal 2, aredridel.projects(true).size
240
+ assert_equal 2, aredridel.projects.reload.size
218
241
  end
219
242
 
220
243
  def test_habtm_adding_before_save
@@ -229,7 +252,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
229
252
  assert_equal no_of_devels+1, Developer.count
230
253
  assert_equal no_of_projects+1, Project.count
231
254
  assert_equal 2, aredridel.projects.size
232
- assert_equal 2, aredridel.projects(true).size
255
+ assert_equal 2, aredridel.projects.reload.size
233
256
  end
234
257
 
235
258
  def test_habtm_saving_multiple_relationships
@@ -246,7 +269,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
246
269
  assert_equal developers, new_project.developers
247
270
  end
248
271
 
249
- def test_habtm_unique_order_preserved
272
+ def test_habtm_distinct_order_preserved
250
273
  assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).non_unique_developers
251
274
  assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).developers
252
275
  end
@@ -351,7 +374,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
351
374
  assert_equal 'Yet Another Testing Title', another_post.title
352
375
  end
353
376
 
354
- def test_uniq_after_the_fact
377
+ def test_distinct_after_the_fact
355
378
  dev = developers(:jamis)
356
379
  dev.projects << projects(:active_record)
357
380
  dev.projects << projects(:active_record)
@@ -360,13 +383,13 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
360
383
  assert_equal 1, dev.projects.distinct.size
361
384
  end
362
385
 
363
- def test_uniq_before_the_fact
386
+ def test_distinct_before_the_fact
364
387
  projects(:active_record).developers << developers(:jamis)
365
388
  projects(:active_record).developers << developers(:david)
366
389
  assert_equal 3, projects(:active_record, :reload).developers.size
367
390
  end
368
391
 
369
- def test_uniq_option_prevents_duplicate_push
392
+ def test_distinct_option_prevents_duplicate_push
370
393
  project = projects(:active_record)
371
394
  project.developers << developers(:jamis)
372
395
  project.developers << developers(:david)
@@ -377,7 +400,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
377
400
  assert_equal 3, project.developers.size
378
401
  end
379
402
 
380
- def test_uniq_when_association_already_loaded
403
+ def test_distinct_when_association_already_loaded
381
404
  project = projects(:active_record)
382
405
  project.developers << [ developers(:jamis), developers(:david), developers(:jamis), developers(:david) ]
383
406
  assert_equal 3, Project.includes(:developers).find(project.id).developers.size
@@ -393,8 +416,8 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
393
416
  david.projects.delete(active_record)
394
417
 
395
418
  assert_equal 1, david.projects.size
396
- assert_equal 1, david.projects(true).size
397
- assert_equal 2, active_record.developers(true).size
419
+ assert_equal 1, david.projects.reload.size
420
+ assert_equal 2, active_record.developers.reload.size
398
421
  end
399
422
 
400
423
  def test_deleting_array
@@ -402,7 +425,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
402
425
  david.projects.reload
403
426
  david.projects.delete(Project.all.to_a)
404
427
  assert_equal 0, david.projects.size
405
- assert_equal 0, david.projects(true).size
428
+ assert_equal 0, david.projects.reload.size
406
429
  end
407
430
 
408
431
  def test_deleting_all
@@ -410,7 +433,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
410
433
  david.projects.reload
411
434
  david.projects.clear
412
435
  assert_equal 0, david.projects.size
413
- assert_equal 0, david.projects(true).size
436
+ assert_equal 0, david.projects.reload.size
414
437
  end
415
438
 
416
439
  def test_removing_associations_on_destroy
@@ -436,7 +459,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
436
459
  assert join_records.empty?
437
460
 
438
461
  assert_equal 1, david.reload.projects.size
439
- assert_equal 1, david.projects(true).size
462
+ assert_equal 1, david.projects.reload.size
440
463
  end
441
464
 
442
465
  def test_destroying_many
@@ -452,7 +475,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
452
475
  assert join_records.empty?
453
476
 
454
477
  assert_equal 0, david.reload.projects.size
455
- assert_equal 0, david.projects(true).size
478
+ assert_equal 0, david.projects.reload.size
456
479
  end
457
480
 
458
481
  def test_destroy_all
@@ -468,7 +491,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
468
491
  assert join_records.empty?
469
492
 
470
493
  assert david.projects.empty?
471
- assert david.projects(true).empty?
494
+ assert david.projects.reload.empty?
472
495
  end
473
496
 
474
497
  def test_destroy_associations_destroys_multiple_associations
@@ -484,11 +507,11 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
484
507
 
485
508
  join_records = Parrot.connection.select_all("SELECT * FROM parrots_pirates WHERE parrot_id = #{george.id}")
486
509
  assert join_records.empty?
487
- assert george.pirates(true).empty?
510
+ assert george.pirates.reload.empty?
488
511
 
489
512
  join_records = Parrot.connection.select_all("SELECT * FROM parrots_treasures WHERE parrot_id = #{george.id}")
490
513
  assert join_records.empty?
491
- assert george.treasures(true).empty?
514
+ assert george.treasures.reload.empty?
492
515
  end
493
516
 
494
517
  def test_associations_with_conditions
@@ -567,7 +590,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
567
590
 
568
591
  def test_dynamic_find_all_should_respect_readonly_access
569
592
  projects(:active_record).readonly_developers.each { |d| assert_raise(ActiveRecord::ReadOnlyRecord) { d.save! } if d.valid?}
570
- projects(:active_record).readonly_developers.each { |d| d.readonly? }
593
+ projects(:active_record).readonly_developers.each(&:readonly?)
571
594
  end
572
595
 
573
596
  def test_new_with_values_in_collection
@@ -656,7 +679,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
656
679
  end
657
680
 
658
681
  def test_habtm_respects_select
659
- categories(:technology).select_testing_posts(true).each do |o|
682
+ categories(:technology).select_testing_posts.reload.each do |o|
660
683
  assert_respond_to o, :correctness_marker
661
684
  end
662
685
  assert_respond_to categories(:technology).select_testing_posts.first, :correctness_marker
@@ -728,7 +751,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
728
751
 
729
752
  def test_get_ids_for_loaded_associations
730
753
  developer = developers(:david)
731
- developer.projects(true)
754
+ developer.projects.reload
732
755
  assert_queries(0) do
733
756
  developer.project_ids
734
757
  developer.project_ids
@@ -796,9 +819,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
796
819
  end
797
820
 
798
821
  def test_association_proxy_transaction_method_starts_transaction_in_association_class
799
- Post.expects(:transaction)
800
- Category.first.posts.transaction do
801
- # nothing
822
+ assert_called(Post, :transaction) do
823
+ Category.first.posts.transaction do
824
+ # nothing
825
+ end
802
826
  end
803
827
  end
804
828
 
@@ -817,12 +841,12 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
817
841
  assert_no_queries { david.projects.columns }
818
842
  end
819
843
 
820
- def test_attributes_are_being_set_when_initialized_from_habm_association_with_where_clause
844
+ def test_attributes_are_being_set_when_initialized_from_habtm_association_with_where_clause
821
845
  new_developer = projects(:action_controller).developers.where(:name => "Marcelo").build
822
846
  assert_equal new_developer.name, "Marcelo"
823
847
  end
824
848
 
825
- def test_attributes_are_being_set_when_initialized_from_habm_association_with_multiple_where_clauses
849
+ def test_attributes_are_being_set_when_initialized_from_habtm_association_with_multiple_where_clauses
826
850
  new_developer = projects(:action_controller).developers.where(:name => "Marcelo").where(:salary => 90_000).build
827
851
  assert_equal new_developer.name, "Marcelo"
828
852
  assert_equal new_developer.salary, 90_000
@@ -915,11 +939,17 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
915
939
  end
916
940
 
917
941
  def test_with_symbol_class_name
918
- assert_nothing_raised NoMethodError do
942
+ assert_nothing_raised do
919
943
  DeveloperWithSymbolClassName.new
920
944
  end
921
945
  end
922
946
 
947
+ def test_association_force_reload_with_only_true_is_deprecated
948
+ developer = Developer.find(1)
949
+
950
+ assert_deprecated { developer.projects(true) }
951
+ end
952
+
923
953
  def test_alternate_database
924
954
  professor = Professor.create(name: "Plum")
925
955
  course = Course.create(name: "Forensics")
@@ -929,4 +959,46 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
929
959
  end
930
960
  assert_equal 1, professor.courses.count
931
961
  end
962
+
963
+ def test_habtm_scope_can_unscope
964
+ project = ProjectUnscopingDavidDefaultScope.new
965
+ project.save!
966
+
967
+ developer = LazyBlockDeveloperCalledDavid.new(name: "Not David")
968
+ developer.save!
969
+ project.developers << developer
970
+
971
+ projects = ProjectUnscopingDavidDefaultScope.includes(:developers).where(id: project.id)
972
+ assert_equal 1, projects.first.developers.size
973
+ end
974
+
975
+ def test_preloaded_associations_size
976
+ assert_equal Project.first.salaried_developers.size,
977
+ Project.preload(:salaried_developers).first.salaried_developers.size
978
+
979
+ assert_equal Project.includes(:salaried_developers).references(:salaried_developers).first.salaried_developers.size,
980
+ Project.preload(:salaried_developers).first.salaried_developers.size
981
+
982
+ # Nested HATBM
983
+ first_project = Developer.first.projects.first
984
+ preloaded_first_project =
985
+ Developer.preload(projects: :salaried_developers).
986
+ first.
987
+ projects.
988
+ detect { |p| p.id == first_project.id }
989
+
990
+ assert preloaded_first_project.salaried_developers.loaded?, true
991
+ assert_equal first_project.salaried_developers.size, preloaded_first_project.salaried_developers.size
992
+ end
993
+
994
+ def test_has_and_belongs_to_many_is_useable_with_belongs_to_required_by_default
995
+ assert_difference "Project.first.developers_required_by_default.size", 1 do
996
+ Project.first.developers_required_by_default.create!(name: "Sean", salary: 50000)
997
+ end
998
+ end
999
+
1000
+ def test_association_name_is_the_same_as_join_table_name
1001
+ user = User.create!
1002
+ assert_nothing_raised { user.jobs_pool.clear }
1003
+ end
932
1004
  end
@@ -30,6 +30,7 @@ require 'models/college'
30
30
  require 'models/student'
31
31
  require 'models/pirate'
32
32
  require 'models/ship'
33
+ require 'models/ship_part'
33
34
  require 'models/treasure'
34
35
  require 'models/parrot'
35
36
  require 'models/tyre'
@@ -39,7 +40,7 @@ require 'models/zine'
39
40
  require 'models/interest'
40
41
 
41
42
  class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCase
42
- fixtures :authors, :posts, :comments, :author_addresses
43
+ fixtures :authors, :posts, :comments
43
44
 
44
45
  def test_should_generate_valid_sql
45
46
  author = authors(:david)
@@ -60,7 +61,7 @@ class HasManyAssociationsTestPrimaryKeys < ActiveRecord::TestCase
60
61
  assert_equal 2, subscriber.subscriptions.size
61
62
  end
62
63
 
63
- assert_equal subscriber.subscriptions, Subscription.where(subscriber_id: 'webster132')
64
+ assert_equal Subscription.where(subscriber_id: "webster132"), subscriber.subscriptions
64
65
  end
65
66
 
66
67
  def test_association_primary_key_on_new_record_should_fetch_with_query
@@ -71,12 +72,23 @@ class HasManyAssociationsTestPrimaryKeys < ActiveRecord::TestCase
71
72
  assert_equal 1, author.essays.size
72
73
  end
73
74
 
74
- assert_equal author.essays, Essay.where(writer_id: "David")
75
+ assert_equal Essay.where(writer_id: "David"), author.essays
75
76
  end
76
77
 
77
78
  def test_has_many_custom_primary_key
78
79
  david = authors(:david)
79
- assert_equal david.essays, Essay.where(writer_id: "David")
80
+ assert_equal Essay.where(writer_id: "David"), david.essays
81
+ end
82
+
83
+ def test_ids_on_unloaded_association_with_custom_primary_key
84
+ david = people(:david)
85
+ assert_equal Essay.where(writer_id: "David").pluck(:id), david.essay_ids
86
+ end
87
+
88
+ def test_ids_on_loaded_association_with_custom_primary_key
89
+ david = people(:david)
90
+ david.essays.load
91
+ assert_equal Essay.where(writer_id: "David").pluck(:id), david.essay_ids
80
92
  end
81
93
 
82
94
  def test_has_many_assignment_with_custom_primary_key
@@ -164,6 +176,32 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
164
176
  assert_equal college.students, Student.where(active: true, college_id: college.id)
165
177
  end
166
178
 
179
+ def test_add_record_to_collection_should_change_its_updated_at
180
+ ship = Ship.create(name: 'dauntless')
181
+ part = ShipPart.create(name: 'cockpit')
182
+ updated_at = part.updated_at
183
+
184
+ travel(1.second) do
185
+ ship.parts << part
186
+ end
187
+
188
+ assert_equal part.ship, ship
189
+ assert_not_equal part.updated_at, updated_at
190
+ end
191
+
192
+ def test_clear_collection_should_not_change_updated_at
193
+ # GH#17161: .clear calls delete_all (and returns the association),
194
+ # which is intended to not touch associated objects's updated_at field
195
+ ship = Ship.create(name: 'dauntless')
196
+ part = ShipPart.create(name: 'cockpit', ship_id: ship.id)
197
+
198
+ ship.parts.clear
199
+ part.reload
200
+
201
+ assert_equal nil, part.ship
202
+ assert !part.updated_at_changed?
203
+ end
204
+
167
205
  def test_create_from_association_should_respect_default_scope
168
206
  car = Car.create(:name => 'honda')
169
207
  assert_equal 'honda', car.name
@@ -176,9 +214,22 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
176
214
 
177
215
  bulb = car.bulbs.create
178
216
  assert_equal 'defaulty', bulb.name
217
+ end
218
+
219
+ def test_build_and_create_from_association_should_respect_passed_attributes_over_default_scope
220
+ car = Car.create(name: 'honda')
179
221
 
180
- bulb = car.bulbs.create(:name => 'exotic')
222
+ bulb = car.bulbs.build(name: 'exotic')
181
223
  assert_equal 'exotic', bulb.name
224
+
225
+ bulb = car.bulbs.create(name: 'exotic')
226
+ assert_equal 'exotic', bulb.name
227
+
228
+ bulb = car.awesome_bulbs.build(frickinawesome: false)
229
+ assert_equal false, bulb.frickinawesome
230
+
231
+ bulb = car.awesome_bulbs.create(frickinawesome: false)
232
+ assert_equal false, bulb.frickinawesome
182
233
  end
183
234
 
184
235
  def test_build_from_association_should_respect_scope
@@ -320,16 +371,16 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
320
371
  # would be convenient), because this would cause that scope to be applied to any callbacks etc.
321
372
  def test_build_and_create_should_not_happen_within_scope
322
373
  car = cars(:honda)
323
- scoped_count = car.foo_bulbs.where_values.count
374
+ scope = car.foo_bulbs.where_values_hash
324
375
 
325
376
  bulb = car.foo_bulbs.build
326
- assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
377
+ assert_not_equal scope, bulb.scope_after_initialize.where_values_hash
327
378
 
328
379
  bulb = car.foo_bulbs.create
329
- assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
380
+ assert_not_equal scope, bulb.scope_after_initialize.where_values_hash
330
381
 
331
382
  bulb = car.foo_bulbs.create!
332
- assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
383
+ assert_not_equal scope, bulb.scope_after_initialize.where_values_hash
333
384
  end
334
385
 
335
386
  def test_no_sql_should_be_fired_if_association_already_loaded
@@ -367,6 +418,16 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
367
418
  bulbs.forty_two({})
368
419
  end
369
420
 
421
+ assert_no_queries do
422
+ bulbs.third_to_last()
423
+ bulbs.third_to_last({})
424
+ end
425
+
426
+ assert_no_queries do
427
+ bulbs.second_to_last()
428
+ bulbs.second_to_last({})
429
+ end
430
+
370
431
  assert_no_queries do
371
432
  bulbs.last()
372
433
  bulbs.last({})
@@ -388,6 +449,26 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
388
449
  assert_equal person, person.readers.first.person
389
450
  end
390
451
 
452
+ def test_update_all_respects_association_scope
453
+ person = Person.new
454
+ person.first_name = 'Naruto'
455
+ person.references << Reference.new
456
+ person.id = 10
457
+ person.references
458
+ person.save!
459
+ assert_equal 1, person.references.update_all(favourite: true)
460
+ end
461
+
462
+ def test_exists_respects_association_scope
463
+ person = Person.new
464
+ person.first_name = 'Sasuke'
465
+ person.references << Reference.new
466
+ person.id = 10
467
+ person.references
468
+ person.save!
469
+ assert_predicate person.references, :exists?
470
+ end
471
+
391
472
  def force_signal37_to_load_all_clients_of_firm
392
473
  companies(:first_firm).clients_of_firm.each {|f| }
393
474
  end
@@ -508,10 +589,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
508
589
  end
509
590
 
510
591
  def test_update_all_on_association_accessed_before_save
511
- firm = Firm.new(name: 'Firm')
592
+ firm = Firm.new(name: "Firm")
512
593
  firm.clients << Client.first
513
594
  firm.save!
514
- assert_equal firm.clients.count, firm.clients.update_all(description: 'Great!')
595
+ assert_equal firm.clients.count, firm.clients.update_all(description: "Great!")
596
+ end
597
+
598
+ def test_update_all_on_association_accessed_before_save_with_explicit_foreign_key
599
+ firm = Firm.new(name: "Firm", id: 100)
600
+ firm.clients << Client.first
601
+ firm.save!
602
+ assert_equal firm.clients.count, firm.clients.update_all(description: "Great!")
515
603
  end
516
604
 
517
605
  def test_belongs_to_sanity
@@ -539,6 +627,18 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
539
627
  assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(2, 99) }
540
628
  end
541
629
 
630
+ def test_find_one_message_on_primary_key
631
+ firm = Firm.all.merge!(order: "id").first
632
+
633
+ e = assert_raises(ActiveRecord::RecordNotFound) do
634
+ firm.clients.find(0)
635
+ end
636
+ assert_equal 0, e.id
637
+ assert_equal "id", e.primary_key
638
+ assert_equal "Client", e.model
639
+ assert_match (/\ACouldn't find Client with 'id'=0/), e.message
640
+ end
641
+
542
642
  def test_find_ids_and_inverse_of
543
643
  force_signal37_to_load_all_clients_of_firm
544
644
 
@@ -669,7 +769,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
669
769
  natural = Client.new("name" => "Natural Company")
670
770
  companies(:first_firm).clients_of_firm << natural
671
771
  assert_equal 3, companies(:first_firm).clients_of_firm.size # checking via the collection
672
- assert_equal 3, companies(:first_firm).clients_of_firm(true).size # checking using the db
772
+ assert_equal 3, companies(:first_firm).clients_of_firm.reload.size # checking using the db
673
773
  assert_equal natural, companies(:first_firm).clients_of_firm.last
674
774
  end
675
775
 
@@ -724,7 +824,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
724
824
  force_signal37_to_load_all_clients_of_firm
725
825
  companies(:first_firm).clients_of_firm.concat([Client.new("name" => "Natural Company"), Client.new("name" => "Apple")])
726
826
  assert_equal 4, companies(:first_firm).clients_of_firm.size
727
- assert_equal 4, companies(:first_firm).clients_of_firm(true).size
827
+ assert_equal 4, companies(:first_firm).clients_of_firm.reload.size
728
828
  end
729
829
 
730
830
  def test_transactions_when_adding_to_persisted
@@ -736,7 +836,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
736
836
  rescue Client::RaisedOnSave
737
837
  end
738
838
 
739
- assert !companies(:first_firm).clients_of_firm(true).include?(good)
839
+ assert !companies(:first_firm).clients_of_firm.reload.include?(good)
740
840
  end
741
841
 
742
842
  def test_transactions_when_adding_to_new_record
@@ -868,12 +968,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
868
968
  new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client")
869
969
  assert new_client.persisted?
870
970
  assert_equal new_client, companies(:first_firm).clients_of_firm.last
871
- assert_equal new_client, companies(:first_firm).clients_of_firm(true).last
971
+ assert_equal new_client, companies(:first_firm).clients_of_firm.reload.last
872
972
  end
873
973
 
874
974
  def test_create_many
875
975
  companies(:first_firm).clients_of_firm.create([{"name" => "Another Client"}, {"name" => "Another Client II"}])
876
- assert_equal 4, companies(:first_firm).clients_of_firm(true).size
976
+ assert_equal 4, companies(:first_firm).clients_of_firm.reload.size
877
977
  end
878
978
 
879
979
  def test_create_followed_by_save_does_not_load_target
@@ -886,7 +986,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
886
986
  force_signal37_to_load_all_clients_of_firm
887
987
  companies(:first_firm).clients_of_firm.delete(companies(:first_firm).clients_of_firm.first)
888
988
  assert_equal 1, companies(:first_firm).clients_of_firm.size
889
- assert_equal 1, companies(:first_firm).clients_of_firm(true).size
989
+ assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
890
990
  end
891
991
 
892
992
  def test_deleting_before_save
@@ -902,7 +1002,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
902
1002
  # option is not given on the association.
903
1003
  ship = Ship.create(name: 'Countless', treasures_count: 10)
904
1004
 
905
- assert_not ship.treasures.instance_variable_get('@association').send(:has_cached_counter?)
1005
+ assert_not Ship.reflect_on_association(:treasures).has_cached_counter?
906
1006
 
907
1007
  # Count should come from sql count() of treasures rather than treasures_count attribute
908
1008
  assert_equal ship.treasures.size, 0
@@ -1042,7 +1142,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1042
1142
  assert_equal 3, companies(:first_firm).clients_of_firm.size
1043
1143
  companies(:first_firm).clients_of_firm.delete([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1], companies(:first_firm).clients_of_firm[2]])
1044
1144
  assert_equal 0, companies(:first_firm).clients_of_firm.size
1045
- assert_equal 0, companies(:first_firm).clients_of_firm(true).size
1145
+ assert_equal 0, companies(:first_firm).clients_of_firm.reload.size
1046
1146
  end
1047
1147
 
1048
1148
  def test_delete_all
@@ -1063,7 +1163,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1063
1163
  companies(:first_firm).clients_of_firm.reset
1064
1164
  companies(:first_firm).clients_of_firm.delete_all
1065
1165
  assert_equal 0, companies(:first_firm).clients_of_firm.size
1066
- assert_equal 0, companies(:first_firm).clients_of_firm(true).size
1166
+ assert_equal 0, companies(:first_firm).clients_of_firm.reload.size
1067
1167
  end
1068
1168
 
1069
1169
  def test_transaction_when_deleting_persisted
@@ -1077,7 +1177,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1077
1177
  rescue Client::RaisedOnDestroy
1078
1178
  end
1079
1179
 
1080
- assert_equal [good, bad], companies(:first_firm).clients_of_firm(true)
1180
+ assert_equal [good, bad], companies(:first_firm).clients_of_firm.reload
1081
1181
  end
1082
1182
 
1083
1183
  def test_transaction_when_deleting_new_record
@@ -1097,7 +1197,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1097
1197
  firm.clients_of_firm.clear
1098
1198
 
1099
1199
  assert_equal 0, firm.clients_of_firm.size
1100
- assert_equal 0, firm.clients_of_firm(true).size
1200
+ assert_equal 0, firm.clients_of_firm.reload.size
1101
1201
  assert_equal [], Client.destroyed_client_ids[firm.id]
1102
1202
 
1103
1203
  # Should not be destroyed since the association is not dependent.
@@ -1133,7 +1233,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1133
1233
  firm.dependent_clients_of_firm.clear
1134
1234
 
1135
1235
  assert_equal 0, firm.dependent_clients_of_firm.size
1136
- assert_equal 0, firm.dependent_clients_of_firm(true).size
1236
+ assert_equal 0, firm.dependent_clients_of_firm.reload.size
1137
1237
  assert_equal [], Client.destroyed_client_ids[firm.id]
1138
1238
 
1139
1239
  # Should be destroyed since the association is dependent.
@@ -1166,7 +1266,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1166
1266
  firm.exclusively_dependent_clients_of_firm.clear
1167
1267
 
1168
1268
  assert_equal 0, firm.exclusively_dependent_clients_of_firm.size
1169
- assert_equal 0, firm.exclusively_dependent_clients_of_firm(true).size
1269
+ assert_equal 0, firm.exclusively_dependent_clients_of_firm.reload.size
1170
1270
  # no destroy-filters should have been called
1171
1271
  assert_equal [], Client.destroyed_client_ids[firm.id]
1172
1272
 
@@ -1215,7 +1315,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1215
1315
  # break the vanilla firm_id foreign key
1216
1316
  assert_equal 3, firm.clients.count
1217
1317
  firm.clients.first.update_columns(firm_id: nil)
1218
- assert_equal 2, firm.clients(true).count
1318
+ assert_equal 2, firm.clients.reload.count
1219
1319
  assert_equal 2, firm.clients_using_primary_key_with_delete_all.count
1220
1320
  old_record = firm.clients_using_primary_key_with_delete_all.first
1221
1321
  firm = Firm.first
@@ -1241,7 +1341,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1241
1341
  firm.clients_of_firm.clear
1242
1342
 
1243
1343
  assert_equal 0, firm.clients_of_firm.size
1244
- assert_equal 0, firm.clients_of_firm(true).size
1344
+ assert_equal 0, firm.clients_of_firm.reload.size
1245
1345
  end
1246
1346
 
1247
1347
  def test_deleting_a_item_which_is_not_in_the_collection
@@ -1249,11 +1349,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1249
1349
  summit = Client.find_by_name('Summit')
1250
1350
  companies(:first_firm).clients_of_firm.delete(summit)
1251
1351
  assert_equal 2, companies(:first_firm).clients_of_firm.size
1252
- assert_equal 2, companies(:first_firm).clients_of_firm(true).size
1352
+ assert_equal 2, companies(:first_firm).clients_of_firm.reload.size
1253
1353
  assert_equal 2, summit.client_of
1254
1354
  end
1255
1355
 
1256
- def test_deleting_by_fixnum_id
1356
+ def test_deleting_by_integer_id
1257
1357
  david = Developer.find(1)
1258
1358
 
1259
1359
  assert_difference 'david.projects.count', -1 do
@@ -1287,10 +1387,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1287
1387
  end
1288
1388
 
1289
1389
  assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1290
- assert_equal 1, companies(:first_firm).clients_of_firm(true).size
1390
+ assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
1291
1391
  end
1292
1392
 
1293
- def test_destroying_by_fixnum_id
1393
+ def test_destroying_by_integer_id
1294
1394
  force_signal37_to_load_all_clients_of_firm
1295
1395
 
1296
1396
  assert_difference "Client.count", -1 do
@@ -1298,7 +1398,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1298
1398
  end
1299
1399
 
1300
1400
  assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1301
- assert_equal 1, companies(:first_firm).clients_of_firm(true).size
1401
+ assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
1302
1402
  end
1303
1403
 
1304
1404
  def test_destroying_by_string_id
@@ -1309,7 +1409,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1309
1409
  end
1310
1410
 
1311
1411
  assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1312
- assert_equal 1, companies(:first_firm).clients_of_firm(true).size
1412
+ assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
1313
1413
  end
1314
1414
 
1315
1415
  def test_destroying_a_collection
@@ -1322,7 +1422,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1322
1422
  end
1323
1423
 
1324
1424
  assert_equal 1, companies(:first_firm).reload.clients_of_firm.size
1325
- assert_equal 1, companies(:first_firm).clients_of_firm(true).size
1425
+ assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
1326
1426
  end
1327
1427
 
1328
1428
  def test_destroy_all
@@ -1331,9 +1431,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1331
1431
  assert !clients.empty?, "37signals has clients after load"
1332
1432
  destroyed = companies(:first_firm).clients_of_firm.destroy_all
1333
1433
  assert_equal clients.sort_by(&:id), destroyed.sort_by(&:id)
1334
- assert destroyed.all? { |client| client.frozen? }, "destroyed clients should be frozen"
1434
+ assert destroyed.all?(&:frozen?), "destroyed clients should be frozen"
1335
1435
  assert companies(:first_firm).clients_of_firm.empty?, "37signals has no clients after destroy all"
1336
- assert companies(:first_firm).clients_of_firm(true).empty?, "37signals has no clients after destroy all and refresh"
1436
+ assert companies(:first_firm).clients_of_firm.reload.empty?, "37signals has no clients after destroy all and refresh"
1337
1437
  end
1338
1438
 
1339
1439
  def test_dependence
@@ -1369,7 +1469,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1369
1469
  assert_nothing_raised { topic.destroy }
1370
1470
  end
1371
1471
 
1372
- uses_transaction :test_dependence_with_transaction_support_on_failure
1373
1472
  def test_dependence_with_transaction_support_on_failure
1374
1473
  firm = companies(:first_firm)
1375
1474
  clients = firm.clients
@@ -1411,6 +1510,26 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1411
1510
  assert firm.companies.exists?(:name => 'child')
1412
1511
  end
1413
1512
 
1513
+ def test_restrict_with_error_is_deprecated_using_key_many
1514
+ I18n.backend = I18n::Backend::Simple.new
1515
+ I18n.backend.store_translations :en, activerecord: { errors: { messages: { restrict_dependent_destroy: { many: 'message for deprecated key' } } } }
1516
+
1517
+ firm = RestrictedWithErrorFirm.create!(name: 'restrict')
1518
+ firm.companies.create(name: 'child')
1519
+
1520
+ assert !firm.companies.empty?
1521
+
1522
+ assert_deprecated { firm.destroy }
1523
+
1524
+ assert !firm.errors.empty?
1525
+
1526
+ assert_equal 'message for deprecated key', firm.errors[:base].first
1527
+ assert RestrictedWithErrorFirm.exists?(name: 'restrict')
1528
+ assert firm.companies.exists?(name: 'child')
1529
+ ensure
1530
+ I18n.backend.reload!
1531
+ end
1532
+
1414
1533
  def test_restrict_with_error
1415
1534
  firm = RestrictedWithErrorFirm.create!(:name => 'restrict')
1416
1535
  firm.companies.create(:name => 'child')
@@ -1426,6 +1545,25 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1426
1545
  assert firm.companies.exists?(:name => 'child')
1427
1546
  end
1428
1547
 
1548
+ def test_restrict_with_error_with_locale
1549
+ I18n.backend = I18n::Backend::Simple.new
1550
+ I18n.backend.store_translations 'en', activerecord: {attributes: {restricted_with_error_firm: {companies: 'client companies'}}}
1551
+ firm = RestrictedWithErrorFirm.create!(name: 'restrict')
1552
+ firm.companies.create(name: 'child')
1553
+
1554
+ assert !firm.companies.empty?
1555
+
1556
+ firm.destroy
1557
+
1558
+ assert !firm.errors.empty?
1559
+
1560
+ assert_equal "Cannot delete record because dependent client companies exist", firm.errors[:base].first
1561
+ assert RestrictedWithErrorFirm.exists?(name: 'restrict')
1562
+ assert firm.companies.exists?(name: 'child')
1563
+ ensure
1564
+ I18n.backend.reload!
1565
+ end
1566
+
1429
1567
  def test_included_in_collection
1430
1568
  assert_equal true, companies(:first_firm).clients.include?(Client.find(2))
1431
1569
  end
@@ -1488,6 +1626,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1488
1626
  assert_queries(0, ignore_none: true) do
1489
1627
  firm.clients = []
1490
1628
  end
1629
+
1630
+ assert_equal [], firm.send('clients=', [])
1491
1631
  end
1492
1632
 
1493
1633
  def test_transactions_when_replacing_on_persisted
@@ -1501,7 +1641,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1501
1641
  rescue Client::RaisedOnSave
1502
1642
  end
1503
1643
 
1504
- assert_equal [good], companies(:first_firm).clients_of_firm(true)
1644
+ assert_equal [good], companies(:first_firm).clients_of_firm.reload
1505
1645
  end
1506
1646
 
1507
1647
  def test_transactions_when_replacing_on_new_record
@@ -1517,7 +1657,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1517
1657
 
1518
1658
  def test_get_ids_for_loaded_associations
1519
1659
  company = companies(:first_firm)
1520
- company.clients(true)
1660
+ company.clients.reload
1521
1661
  assert_queries(0) do
1522
1662
  company.client_ids
1523
1663
  company.client_ids
@@ -1571,7 +1711,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1571
1711
  firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, '']
1572
1712
  firm.save!
1573
1713
 
1574
- assert_equal 2, firm.clients(true).size
1714
+ assert_equal 2, firm.clients.reload.size
1575
1715
  assert_equal true, firm.clients.include?(companies(:second_client))
1576
1716
  end
1577
1717
 
@@ -1741,6 +1881,82 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1741
1881
  assert_equal 3, firm.clients.size
1742
1882
  end
1743
1883
 
1884
+ def test_calling_none_should_count_instead_of_loading_association
1885
+ firm = companies(:first_firm)
1886
+ assert_queries(1) do
1887
+ firm.clients.none? # use count query
1888
+ end
1889
+ assert !firm.clients.loaded?
1890
+ end
1891
+
1892
+ def test_calling_none_on_loaded_association_should_not_use_query
1893
+ firm = companies(:first_firm)
1894
+ firm.clients.collect # force load
1895
+ assert_no_queries { assert ! firm.clients.none? }
1896
+ end
1897
+
1898
+ def test_calling_none_should_defer_to_collection_if_using_a_block
1899
+ firm = companies(:first_firm)
1900
+ assert_queries(1) do
1901
+ firm.clients.expects(:size).never
1902
+ firm.clients.none? { true }
1903
+ end
1904
+ assert firm.clients.loaded?
1905
+ end
1906
+
1907
+ def test_calling_none_should_return_true_if_none
1908
+ firm = companies(:another_firm)
1909
+ assert firm.clients_like_ms.none?
1910
+ assert_equal 0, firm.clients_like_ms.size
1911
+ end
1912
+
1913
+ def test_calling_none_should_return_false_if_any
1914
+ firm = companies(:first_firm)
1915
+ assert !firm.limited_clients.none?
1916
+ assert_equal 1, firm.limited_clients.size
1917
+ end
1918
+
1919
+ def test_calling_one_should_count_instead_of_loading_association
1920
+ firm = companies(:first_firm)
1921
+ assert_queries(1) do
1922
+ firm.clients.one? # use count query
1923
+ end
1924
+ assert !firm.clients.loaded?
1925
+ end
1926
+
1927
+ def test_calling_one_on_loaded_association_should_not_use_query
1928
+ firm = companies(:first_firm)
1929
+ firm.clients.collect # force load
1930
+ assert_no_queries { assert ! firm.clients.one? }
1931
+ end
1932
+
1933
+ def test_calling_one_should_defer_to_collection_if_using_a_block
1934
+ firm = companies(:first_firm)
1935
+ assert_queries(1) do
1936
+ firm.clients.expects(:size).never
1937
+ firm.clients.one? { true }
1938
+ end
1939
+ assert firm.clients.loaded?
1940
+ end
1941
+
1942
+ def test_calling_one_should_return_false_if_zero
1943
+ firm = companies(:another_firm)
1944
+ assert ! firm.clients_like_ms.one?
1945
+ assert_equal 0, firm.clients_like_ms.size
1946
+ end
1947
+
1948
+ def test_calling_one_should_return_true_if_one
1949
+ firm = companies(:first_firm)
1950
+ assert firm.limited_clients.one?
1951
+ assert_equal 1, firm.limited_clients.size
1952
+ end
1953
+
1954
+ def test_calling_one_should_return_false_if_more_than_one
1955
+ firm = companies(:first_firm)
1956
+ assert ! firm.clients.one?
1957
+ assert_equal 3, firm.clients.size
1958
+ end
1959
+
1744
1960
  def test_joins_with_namespaced_model_should_use_correct_type
1745
1961
  old = ActiveRecord::Base.store_full_sti_class
1746
1962
  ActiveRecord::Base.store_full_sti_class = true
@@ -1990,7 +2206,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
1990
2206
  test "association with extend option with multiple extensions" do
1991
2207
  post = posts(:welcome)
1992
2208
  assert_equal "lifo", post.comments_with_extend_2.author
1993
- assert_equal "hello", post.comments_with_extend_2.greeting
2209
+ assert_equal "hullo", post.comments_with_extend_2.greeting
2210
+ end
2211
+
2212
+ test "extend option affects per association" do
2213
+ post = posts(:welcome)
2214
+ assert_equal "lifo", post.comments_with_extend.author
2215
+ assert_equal "lifo", post.comments_with_extend_2.author
2216
+ assert_equal "hello", post.comments_with_extend.greeting
2217
+ assert_equal "hullo", post.comments_with_extend_2.greeting
1994
2218
  end
1995
2219
 
1996
2220
  test "delete record with complex joins" do
@@ -2026,12 +2250,33 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
2026
2250
  assert_equal [bulb1, bulb2], car.all_bulbs.sort_by(&:id)
2027
2251
  end
2028
2252
 
2253
+ test "can unscope and where the default scope of the associated model" do
2254
+ Car.has_many :other_bulbs, -> { unscope(where: [:name]).where(name: 'other') }, class_name: "Bulb"
2255
+ car = Car.create!
2256
+ bulb1 = Bulb.create! name: "defaulty", car: car
2257
+ bulb2 = Bulb.create! name: "other", car: car
2258
+
2259
+ assert_equal [bulb1], car.bulbs
2260
+ assert_equal [bulb2], car.other_bulbs
2261
+ end
2262
+
2263
+ test "can rewhere the default scope of the associated model" do
2264
+ Car.has_many :old_bulbs, -> { rewhere(name: 'old') }, class_name: "Bulb"
2265
+ car = Car.create!
2266
+ bulb1 = Bulb.create! name: "defaulty", car: car
2267
+ bulb2 = Bulb.create! name: "old", car: car
2268
+
2269
+ assert_equal [bulb1], car.bulbs
2270
+ assert_equal [bulb2], car.old_bulbs
2271
+ end
2272
+
2029
2273
  test 'unscopes the default scope of associated model when used with include' do
2030
2274
  car = Car.create!
2031
2275
  bulb = Bulb.create! name: "other", car: car
2032
2276
 
2033
- assert_equal bulb, Car.find(car.id).all_bulbs.first
2034
- assert_equal bulb, Car.includes(:all_bulbs).find(car.id).all_bulbs.first
2277
+ assert_equal [bulb], Car.find(car.id).all_bulbs
2278
+ assert_equal [bulb], Car.includes(:all_bulbs).find(car.id).all_bulbs
2279
+ assert_equal [bulb], Car.eager_load(:all_bulbs).find(car.id).all_bulbs
2035
2280
  end
2036
2281
 
2037
2282
  test "raises RecordNotDestroyed when replaced child can't be destroyed" do
@@ -2083,7 +2328,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
2083
2328
  assert_equal [], authors(:david).posts_with_signature.map(&:title)
2084
2329
  end
2085
2330
 
2086
- test 'associations autosaves when object is already persited' do
2331
+ test 'associations autosaves when object is already persisted' do
2087
2332
  bulb = Bulb.create!
2088
2333
  tyre = Tyre.create!
2089
2334
 
@@ -2159,4 +2404,98 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
2159
2404
 
2160
2405
  assert_equal [first_bulb, second_bulb], car.bulbs
2161
2406
  end
2407
+
2408
+ test "prevent double insertion of new object when the parent association loaded in the after save callback" do
2409
+ reset_callbacks(:save, Bulb) do
2410
+ Bulb.after_save { |record| record.car.bulbs.load }
2411
+
2412
+ car = Car.create!
2413
+ car.bulbs << Bulb.new
2414
+
2415
+ assert_equal 1, car.bulbs.size
2416
+ end
2417
+ end
2418
+
2419
+ test "prevent double firing the before save callback of new object when the parent association saved in the callback" do
2420
+ reset_callbacks(:save, Bulb) do
2421
+ count = 0
2422
+ Bulb.before_save { |record| record.car.save && count += 1 }
2423
+
2424
+ car = Car.create!
2425
+ car.bulbs.create!
2426
+
2427
+ assert_equal 1, count
2428
+ end
2429
+ end
2430
+
2431
+ def test_association_force_reload_with_only_true_is_deprecated
2432
+ company = Company.find(1)
2433
+
2434
+ assert_deprecated { company.clients_of_firm(true) }
2435
+ end
2436
+
2437
+ class AuthorWithErrorDestroyingAssociation < ActiveRecord::Base
2438
+ self.table_name = "authors"
2439
+ has_many :posts_with_error_destroying,
2440
+ class_name: "PostWithErrorDestroying",
2441
+ foreign_key: :author_id,
2442
+ dependent: :destroy
2443
+ end
2444
+
2445
+ class PostWithErrorDestroying < ActiveRecord::Base
2446
+ self.table_name = "posts"
2447
+ self.inheritance_column = nil
2448
+ before_destroy -> { throw :abort }
2449
+ end
2450
+
2451
+ def test_destroy_does_not_raise_when_association_errors_on_destroy
2452
+ assert_no_difference "AuthorWithErrorDestroyingAssociation.count" do
2453
+ author = AuthorWithErrorDestroyingAssociation.first
2454
+
2455
+ assert_not author.destroy
2456
+ end
2457
+ end
2458
+
2459
+ def test_destroy_with_bang_bubbles_errors_from_associations
2460
+ error = assert_raises ActiveRecord::RecordNotDestroyed do
2461
+ AuthorWithErrorDestroyingAssociation.first.destroy!
2462
+ end
2463
+
2464
+ assert_instance_of PostWithErrorDestroying, error.record
2465
+ end
2466
+
2467
+ def test_ids_reader_memoization
2468
+ car = Car.create!(name: 'Tofaş')
2469
+ bulb = Bulb.create!(car: car)
2470
+
2471
+ assert_equal [bulb.id], car.bulb_ids
2472
+ assert_no_queries { car.bulb_ids }
2473
+ end
2474
+
2475
+ def test_loading_association_in_validate_callback_doesnt_affect_persistence
2476
+ reset_callbacks(:validation, Bulb) do
2477
+ Bulb.after_validation { |record| record.car.bulbs.load }
2478
+
2479
+ car = Car.create!(name: "Car")
2480
+ bulb = car.bulbs.create!
2481
+
2482
+ assert_equal [bulb], car.bulbs
2483
+ end
2484
+ end
2485
+
2486
+ private
2487
+
2488
+ def reset_callbacks(kind, klass)
2489
+ old_callbacks = {}
2490
+ old_callbacks[klass] = klass.send("_#{kind}_callbacks").dup
2491
+ klass.subclasses.each do |subclass|
2492
+ old_callbacks[subclass] = subclass.send("_#{kind}_callbacks").dup
2493
+ end
2494
+ yield
2495
+ ensure
2496
+ klass.send("_#{kind}_callbacks=", old_callbacks[klass])
2497
+ klass.subclasses.each do |subclass|
2498
+ subclass.send("_#{kind}_callbacks=", old_callbacks[subclass])
2499
+ end
2500
+ end
2162
2501
  end