ibm_db 3.0.4-x86-mingw32 → 5.0.4-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 (593) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +8 -1
  3. data/LICENSE +1 -1
  4. data/MANIFEST +14 -14
  5. data/ParameterizedQueries README +6 -6
  6. data/README +208 -225
  7. data/ext/Makefile +269 -0
  8. data/ext/Makefile.nt32 +181 -181
  9. data/ext/Makefile.nt32.191 +212 -212
  10. data/ext/extconf.rb +322 -291
  11. data/ext/gil_release_version +3 -0
  12. data/ext/ibm_db-i386-mingw32.def +2 -0
  13. data/ext/ibm_db.c +11879 -11884
  14. data/ext/ibm_db.o +0 -0
  15. data/ext/ibm_db.so +0 -0
  16. data/ext/mkmf.log +110 -0
  17. data/ext/ruby_ibm_db.h +241 -241
  18. data/ext/ruby_ibm_db_cli.c +866 -866
  19. data/ext/ruby_ibm_db_cli.h +500 -500
  20. data/ext/ruby_ibm_db_cli.o +0 -0
  21. data/ext/unicode_support_version +3 -0
  22. data/init.rb +41 -41
  23. data/lib/IBM_DB.rb +27 -27
  24. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3561 -3177
  25. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +5 -2
  26. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  27. data/lib/mswin32/ibm_db.rb +91 -123
  28. data/lib/mswin32/rb2x/i386/ibm_db.so +0 -0
  29. data/test/active_record/connection_adapters/fake_adapter.rb +49 -46
  30. data/test/assets/example.log +1 -1
  31. data/test/assets/test.txt +1 -1
  32. data/test/cases/adapter_test.rb +351 -261
  33. data/test/cases/adapters/mysql2/active_schema_test.rb +193 -0
  34. data/test/cases/adapters/mysql2/bind_parameter_test.rb +50 -0
  35. data/test/cases/adapters/mysql2/boolean_test.rb +100 -0
  36. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +63 -0
  37. data/test/cases/adapters/mysql2/charset_collation_test.rb +54 -0
  38. data/test/cases/adapters/mysql2/connection_test.rb +210 -0
  39. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +45 -0
  40. data/test/cases/adapters/mysql2/enum_test.rb +26 -0
  41. data/test/cases/adapters/mysql2/explain_test.rb +21 -0
  42. data/test/cases/adapters/mysql2/json_test.rb +195 -0
  43. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +83 -0
  44. data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -0
  45. data/test/cases/adapters/mysql2/schema_migrations_test.rb +59 -0
  46. data/test/cases/adapters/mysql2/schema_test.rb +126 -0
  47. data/test/cases/adapters/mysql2/sp_test.rb +36 -0
  48. data/test/cases/adapters/mysql2/sql_types_test.rb +14 -0
  49. data/test/cases/adapters/mysql2/table_options_test.rb +42 -0
  50. data/test/cases/adapters/mysql2/unsigned_type_test.rb +66 -0
  51. data/test/cases/adapters/postgresql/active_schema_test.rb +98 -0
  52. data/test/cases/adapters/postgresql/array_test.rb +339 -0
  53. data/test/cases/adapters/postgresql/bit_string_test.rb +82 -0
  54. data/test/cases/adapters/postgresql/bytea_test.rb +134 -0
  55. data/test/cases/adapters/postgresql/case_insensitive_test.rb +26 -0
  56. data/test/cases/adapters/postgresql/change_schema_test.rb +38 -0
  57. data/test/cases/adapters/postgresql/cidr_test.rb +25 -0
  58. data/test/cases/adapters/postgresql/citext_test.rb +78 -0
  59. data/test/cases/adapters/postgresql/collation_test.rb +53 -0
  60. data/test/cases/adapters/postgresql/composite_test.rb +132 -0
  61. data/test/cases/adapters/postgresql/connection_test.rb +257 -0
  62. data/test/cases/adapters/postgresql/datatype_test.rb +92 -0
  63. data/test/cases/adapters/postgresql/domain_test.rb +47 -0
  64. data/test/cases/adapters/postgresql/enum_test.rb +91 -0
  65. data/test/cases/adapters/postgresql/explain_test.rb +20 -0
  66. data/test/cases/adapters/postgresql/extension_migration_test.rb +63 -0
  67. data/test/cases/adapters/postgresql/full_text_test.rb +44 -0
  68. data/test/cases/adapters/postgresql/geometric_test.rb +378 -0
  69. data/test/cases/adapters/postgresql/hstore_test.rb +382 -0
  70. data/test/cases/adapters/postgresql/infinity_test.rb +69 -0
  71. data/test/cases/adapters/postgresql/integer_test.rb +25 -0
  72. data/test/cases/adapters/postgresql/json_test.rb +237 -0
  73. data/test/cases/adapters/postgresql/ltree_test.rb +53 -0
  74. data/test/cases/adapters/postgresql/money_test.rb +96 -0
  75. data/test/cases/adapters/postgresql/network_test.rb +94 -0
  76. data/test/cases/adapters/postgresql/numbers_test.rb +49 -0
  77. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +405 -0
  78. data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -0
  79. data/test/cases/adapters/postgresql/quoting_test.rb +44 -0
  80. data/test/cases/adapters/postgresql/range_test.rb +343 -0
  81. data/test/cases/adapters/postgresql/referential_integrity_test.rb +111 -0
  82. data/test/cases/adapters/postgresql/rename_table_test.rb +34 -0
  83. data/test/cases/adapters/postgresql/schema_authorization_test.rb +119 -0
  84. data/test/cases/adapters/postgresql/schema_test.rb +597 -0
  85. data/test/cases/adapters/postgresql/serial_test.rb +154 -0
  86. data/test/cases/adapters/postgresql/statement_pool_test.rb +41 -0
  87. data/test/cases/adapters/postgresql/timestamp_test.rb +90 -0
  88. data/test/cases/adapters/postgresql/type_lookup_test.rb +33 -0
  89. data/test/cases/adapters/postgresql/utils_test.rb +62 -0
  90. data/test/cases/adapters/postgresql/uuid_test.rb +294 -0
  91. data/test/cases/adapters/postgresql/xml_test.rb +54 -0
  92. data/test/cases/adapters/sqlite3/collation_test.rb +53 -0
  93. data/test/cases/adapters/sqlite3/copy_table_test.rb +98 -0
  94. data/test/cases/adapters/sqlite3/explain_test.rb +21 -0
  95. data/test/cases/adapters/sqlite3/quoting_test.rb +101 -0
  96. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +441 -0
  97. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -0
  98. data/test/cases/adapters/sqlite3/statement_pool_test.rb +20 -0
  99. data/test/cases/aggregations_test.rb +168 -158
  100. data/test/cases/ar_schema_test.rb +146 -161
  101. data/test/cases/associations/association_scope_test.rb +16 -21
  102. data/test/cases/associations/belongs_to_associations_test.rb +1141 -1029
  103. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +41 -0
  104. data/test/cases/associations/callbacks_test.rb +190 -192
  105. data/test/cases/associations/cascaded_eager_loading_test.rb +188 -188
  106. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -36
  107. data/test/cases/associations/eager_load_nested_include_test.rb +126 -128
  108. data/test/cases/associations/eager_singularization_test.rb +148 -148
  109. data/test/cases/associations/eager_test.rb +1514 -1411
  110. data/test/cases/associations/extension_test.rb +87 -82
  111. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +1004 -932
  112. data/test/cases/associations/has_many_associations_test.rb +2501 -2162
  113. data/test/cases/associations/has_many_through_associations_test.rb +1271 -1204
  114. data/test/cases/associations/has_one_associations_test.rb +707 -610
  115. data/test/cases/associations/has_one_through_associations_test.rb +383 -380
  116. data/test/cases/associations/inner_join_association_test.rb +139 -139
  117. data/test/cases/associations/inverse_associations_test.rb +733 -693
  118. data/test/cases/associations/join_model_test.rb +777 -754
  119. data/test/cases/associations/left_outer_join_association_test.rb +88 -0
  120. data/test/cases/associations/nested_through_associations_test.rb +579 -579
  121. data/test/cases/associations/required_test.rb +102 -82
  122. data/test/cases/associations_test.rb +385 -380
  123. data/test/cases/attribute_decorators_test.rb +126 -125
  124. data/test/cases/attribute_methods/read_test.rb +60 -60
  125. data/test/cases/attribute_methods_test.rb +1009 -952
  126. data/test/cases/attribute_set_test.rb +270 -200
  127. data/test/cases/attribute_test.rb +246 -180
  128. data/test/cases/attributes_test.rb +253 -136
  129. data/test/cases/autosave_association_test.rb +1708 -1595
  130. data/test/cases/base_test.rb +1713 -1638
  131. data/test/cases/batches_test.rb +489 -212
  132. data/test/cases/binary_test.rb +44 -52
  133. data/test/cases/bind_parameter_test.rb +110 -100
  134. data/test/cases/cache_key_test.rb +26 -0
  135. data/test/cases/calculations_test.rb +798 -646
  136. data/test/cases/callbacks_test.rb +636 -543
  137. data/test/cases/clone_test.rb +40 -40
  138. data/test/cases/coders/json_test.rb +15 -0
  139. data/test/cases/coders/yaml_column_test.rb +63 -63
  140. data/test/cases/collection_cache_key_test.rb +115 -0
  141. data/test/cases/column_alias_test.rb +17 -17
  142. data/test/cases/column_definition_test.rb +92 -123
  143. data/test/cases/comment_test.rb +145 -0
  144. data/test/cases/connection_adapters/adapter_leasing_test.rb +56 -54
  145. data/test/cases/connection_adapters/connection_handler_test.rb +160 -53
  146. data/test/cases/connection_adapters/connection_specification_test.rb +12 -12
  147. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +255 -293
  148. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +69 -65
  149. data/test/cases/connection_adapters/quoting_test.rb +13 -13
  150. data/test/cases/connection_adapters/schema_cache_test.rb +61 -56
  151. data/test/cases/connection_adapters/type_lookup_test.rb +118 -110
  152. data/test/cases/connection_management_test.rb +112 -122
  153. data/test/cases/connection_pool_test.rb +521 -346
  154. data/test/cases/connection_specification/resolver_test.rb +131 -116
  155. data/test/cases/core_test.rb +112 -112
  156. data/test/cases/counter_cache_test.rb +214 -209
  157. data/test/cases/custom_locking_test.rb +17 -17
  158. data/test/cases/database_statements_test.rb +34 -19
  159. data/test/cases/{invalid_date_test.rb → date_test.rb} +44 -32
  160. data/test/cases/date_time_precision_test.rb +107 -0
  161. data/test/cases/date_time_test.rb +61 -61
  162. data/test/cases/defaults_test.rb +219 -223
  163. data/test/cases/dirty_test.rb +763 -775
  164. data/test/cases/disconnected_test.rb +30 -28
  165. data/test/cases/dup_test.rb +157 -157
  166. data/test/cases/enum_test.rb +444 -290
  167. data/test/cases/errors_test.rb +16 -0
  168. data/test/cases/explain_subscriber_test.rb +64 -64
  169. data/test/cases/explain_test.rb +87 -76
  170. data/test/cases/finder_respond_to_test.rb +60 -60
  171. data/test/cases/finder_test.rb +1294 -1166
  172. data/test/cases/fixture_set/file_test.rb +156 -138
  173. data/test/cases/fixtures_test.rb +988 -897
  174. data/test/cases/forbidden_attributes_protection_test.rb +165 -99
  175. data/test/cases/habtm_destroy_order_test.rb +61 -61
  176. data/test/cases/helper.rb +204 -210
  177. data/test/cases/hot_compatibility_test.rb +142 -54
  178. data/test/cases/i18n_test.rb +45 -45
  179. data/test/cases/inheritance_test.rb +606 -375
  180. data/test/cases/integration_test.rb +155 -139
  181. data/test/cases/invalid_connection_test.rb +24 -22
  182. data/test/cases/invertible_migration_test.rb +387 -295
  183. data/test/cases/json_serialization_test.rb +311 -302
  184. data/test/cases/locking_test.rb +493 -477
  185. data/test/cases/log_subscriber_test.rb +225 -136
  186. data/test/cases/migration/change_schema_test.rb +458 -472
  187. data/test/cases/migration/change_table_test.rb +256 -224
  188. data/test/cases/migration/column_attributes_test.rb +176 -192
  189. data/test/cases/migration/column_positioning_test.rb +56 -56
  190. data/test/cases/migration/columns_test.rb +310 -304
  191. data/test/cases/migration/command_recorder_test.rb +350 -305
  192. data/test/cases/migration/compatibility_test.rb +118 -0
  193. data/test/cases/migration/create_join_table_test.rb +157 -148
  194. data/test/cases/migration/foreign_key_test.rb +362 -360
  195. data/test/cases/migration/helper.rb +39 -39
  196. data/test/cases/migration/index_test.rb +218 -216
  197. data/test/cases/migration/logger_test.rb +36 -36
  198. data/test/cases/migration/pending_migrations_test.rb +52 -53
  199. data/test/cases/migration/references_foreign_key_test.rb +221 -214
  200. data/test/cases/migration/references_index_test.rb +101 -101
  201. data/test/cases/migration/references_statements_test.rb +136 -116
  202. data/test/cases/migration/rename_table_test.rb +93 -93
  203. data/test/cases/migration_test.rb +1157 -959
  204. data/test/cases/migrator_test.rb +471 -388
  205. data/test/cases/mixin_test.rb +68 -70
  206. data/test/cases/modules_test.rb +172 -173
  207. data/test/cases/multiparameter_attributes_test.rb +372 -350
  208. data/test/cases/multiple_db_test.rb +122 -115
  209. data/test/cases/nested_attributes_test.rb +1098 -1057
  210. data/test/cases/nested_attributes_with_callbacks_test.rb +144 -144
  211. data/test/cases/persistence_test.rb +1001 -909
  212. data/test/cases/pooled_connections_test.rb +81 -81
  213. data/test/cases/primary_keys_test.rb +376 -237
  214. data/test/cases/query_cache_test.rb +446 -326
  215. data/test/cases/quoting_test.rb +202 -156
  216. data/test/cases/readonly_test.rb +119 -118
  217. data/test/cases/reaper_test.rb +85 -85
  218. data/test/cases/reflection_test.rb +509 -454
  219. data/test/cases/relation/delegation_test.rb +63 -68
  220. data/test/cases/relation/merging_test.rb +157 -161
  221. data/test/cases/relation/mutation_test.rb +183 -165
  222. data/test/cases/relation/or_test.rb +92 -0
  223. data/test/cases/relation/predicate_builder_test.rb +16 -14
  224. data/test/cases/relation/record_fetch_warning_test.rb +40 -0
  225. data/test/cases/relation/where_chain_test.rb +105 -181
  226. data/test/cases/relation/where_clause_test.rb +182 -0
  227. data/test/cases/relation/where_test.rb +322 -300
  228. data/test/cases/relation_test.rb +328 -297
  229. data/test/cases/relations_test.rb +2026 -1815
  230. data/test/cases/reload_models_test.rb +22 -22
  231. data/test/cases/result_test.rb +90 -80
  232. data/test/cases/sanitize_test.rb +176 -83
  233. data/test/cases/schema_dumper_test.rb +457 -463
  234. data/test/cases/schema_loading_test.rb +52 -0
  235. data/test/cases/scoping/default_scoping_test.rb +528 -454
  236. data/test/cases/scoping/named_scoping_test.rb +561 -524
  237. data/test/cases/scoping/relation_scoping_test.rb +400 -357
  238. data/test/cases/secure_token_test.rb +32 -0
  239. data/test/cases/serialization_test.rb +104 -104
  240. data/test/cases/serialized_attribute_test.rb +364 -277
  241. data/test/cases/statement_cache_test.rb +136 -98
  242. data/test/cases/store_test.rb +195 -194
  243. data/test/cases/suppressor_test.rb +63 -0
  244. data/test/cases/tasks/database_tasks_test.rb +462 -396
  245. data/test/cases/tasks/mysql_rake_test.rb +345 -311
  246. data/test/cases/tasks/postgresql_rake_test.rb +304 -245
  247. data/test/cases/tasks/sqlite_rake_test.rb +220 -193
  248. data/test/cases/test_case.rb +131 -123
  249. data/test/cases/test_fixtures_test.rb +36 -0
  250. data/test/cases/time_precision_test.rb +103 -0
  251. data/test/cases/timestamp_test.rb +501 -468
  252. data/test/cases/touch_later_test.rb +121 -0
  253. data/test/cases/transaction_callbacks_test.rb +518 -452
  254. data/test/cases/transaction_isolation_test.rb +106 -106
  255. data/test/cases/transactions_test.rb +835 -817
  256. data/test/cases/type/adapter_specific_registry_test.rb +133 -0
  257. data/test/cases/type/date_time_test.rb +14 -0
  258. data/test/cases/type/integer_test.rb +27 -121
  259. data/test/cases/type/string_test.rb +22 -36
  260. data/test/cases/type/type_map_test.rb +177 -177
  261. data/test/cases/type_test.rb +39 -0
  262. data/test/cases/types_test.rb +24 -141
  263. data/test/cases/unconnected_test.rb +33 -33
  264. data/test/cases/validations/absence_validation_test.rb +73 -0
  265. data/test/cases/validations/association_validation_test.rb +97 -86
  266. data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -84
  267. data/test/cases/validations/i18n_validation_test.rb +86 -90
  268. data/test/cases/validations/length_validation_test.rb +79 -47
  269. data/test/cases/validations/presence_validation_test.rb +103 -68
  270. data/test/cases/validations/uniqueness_validation_test.rb +548 -434
  271. data/test/cases/validations_repair_helper.rb +19 -23
  272. data/test/cases/validations_test.rb +194 -165
  273. data/test/cases/view_test.rb +216 -113
  274. data/test/cases/yaml_serialization_test.rb +121 -86
  275. data/test/config.example.yml +97 -0
  276. data/test/config.rb +5 -5
  277. data/test/config.yml +154 -154
  278. data/test/connections/native_ibm_db/connection.rb +43 -43
  279. data/test/fixtures/accounts.yml +29 -29
  280. data/test/fixtures/admin/accounts.yml +2 -2
  281. data/test/fixtures/admin/randomly_named_a9.yml +7 -7
  282. data/test/fixtures/admin/randomly_named_b0.yml +7 -7
  283. data/test/fixtures/admin/users.yml +10 -10
  284. data/test/fixtures/author_addresses.yml +17 -17
  285. data/test/fixtures/author_favorites.yml +3 -3
  286. data/test/fixtures/authors.yml +23 -23
  287. data/test/fixtures/bad_posts.yml +9 -0
  288. data/test/fixtures/binaries.yml +133 -133
  289. data/test/fixtures/books.yml +31 -11
  290. data/test/fixtures/bulbs.yml +5 -5
  291. data/test/fixtures/cars.yml +9 -9
  292. data/test/fixtures/categories.yml +19 -19
  293. data/test/fixtures/categories/special_categories.yml +9 -9
  294. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -4
  295. data/test/fixtures/categories_ordered.yml +7 -7
  296. data/test/fixtures/categories_posts.yml +31 -31
  297. data/test/fixtures/categorizations.yml +23 -23
  298. data/test/fixtures/clubs.yml +8 -8
  299. data/test/fixtures/collections.yml +3 -3
  300. data/test/fixtures/colleges.yml +3 -3
  301. data/test/fixtures/comments.yml +65 -65
  302. data/test/fixtures/companies.yml +67 -67
  303. data/test/fixtures/computers.yml +10 -10
  304. data/test/fixtures/content.yml +3 -0
  305. data/test/fixtures/content_positions.yml +3 -0
  306. data/test/fixtures/courses.yml +8 -8
  307. data/test/fixtures/customers.yml +25 -25
  308. data/test/fixtures/dashboards.yml +6 -6
  309. data/test/fixtures/dead_parrots.yml +5 -0
  310. data/test/fixtures/developers.yml +21 -21
  311. data/test/fixtures/developers_projects.yml +16 -16
  312. data/test/fixtures/dog_lovers.yml +7 -7
  313. data/test/fixtures/dogs.yml +4 -4
  314. data/test/fixtures/doubloons.yml +3 -3
  315. data/test/fixtures/edges.yml +5 -5
  316. data/test/fixtures/entrants.yml +14 -14
  317. data/test/fixtures/essays.yml +6 -6
  318. data/test/fixtures/faces.yml +11 -11
  319. data/test/fixtures/fk_test_has_fk.yml +3 -3
  320. data/test/fixtures/fk_test_has_pk.yml +1 -1
  321. data/test/fixtures/friendships.yml +4 -4
  322. data/test/fixtures/funny_jokes.yml +10 -10
  323. data/test/fixtures/interests.yml +33 -33
  324. data/test/fixtures/items.yml +3 -3
  325. data/test/fixtures/jobs.yml +7 -7
  326. data/test/fixtures/legacy_things.yml +3 -3
  327. data/test/fixtures/live_parrots.yml +4 -0
  328. data/test/fixtures/mateys.yml +4 -4
  329. data/test/fixtures/member_details.yml +8 -8
  330. data/test/fixtures/member_types.yml +6 -6
  331. data/test/fixtures/members.yml +11 -11
  332. data/test/fixtures/memberships.yml +34 -34
  333. data/test/fixtures/men.yml +5 -5
  334. data/test/fixtures/minimalistics.yml +2 -2
  335. data/test/fixtures/minivans.yml +5 -5
  336. data/test/fixtures/mixed_case_monkeys.yml +6 -6
  337. data/test/fixtures/mixins.yml +29 -29
  338. data/test/fixtures/movies.yml +7 -7
  339. data/test/fixtures/naked/yml/accounts.yml +1 -1
  340. data/test/fixtures/naked/yml/companies.yml +1 -1
  341. data/test/fixtures/naked/yml/courses.yml +1 -1
  342. data/test/fixtures/naked/yml/parrots.yml +2 -0
  343. data/test/fixtures/naked/yml/trees.yml +3 -0
  344. data/test/fixtures/nodes.yml +29 -0
  345. data/test/fixtures/organizations.yml +5 -5
  346. data/test/fixtures/other_comments.yml +6 -0
  347. data/test/fixtures/other_dogs.yml +2 -0
  348. data/test/fixtures/other_posts.yml +7 -0
  349. data/test/fixtures/other_topics.yml +42 -42
  350. data/test/fixtures/owners.yml +9 -9
  351. data/test/fixtures/parrots.yml +27 -27
  352. data/test/fixtures/parrots_pirates.yml +7 -7
  353. data/test/fixtures/people.yml +24 -24
  354. data/test/fixtures/peoples_treasures.yml +3 -3
  355. data/test/fixtures/pets.yml +19 -19
  356. data/test/fixtures/pirates.yml +12 -12
  357. data/test/fixtures/posts.yml +80 -80
  358. data/test/fixtures/price_estimates.yml +16 -7
  359. data/test/fixtures/products.yml +4 -4
  360. data/test/fixtures/projects.yml +7 -7
  361. data/test/fixtures/randomly_named_a9.yml +7 -7
  362. data/test/fixtures/ratings.yml +14 -14
  363. data/test/fixtures/readers.yml +11 -11
  364. data/test/fixtures/references.yml +17 -17
  365. data/test/fixtures/reserved_words/distinct.yml +5 -5
  366. data/test/fixtures/reserved_words/distinct_select.yml +11 -11
  367. data/test/fixtures/reserved_words/group.yml +14 -14
  368. data/test/fixtures/reserved_words/select.yml +8 -8
  369. data/test/fixtures/reserved_words/values.yml +7 -7
  370. data/test/fixtures/ships.yml +6 -6
  371. data/test/fixtures/speedometers.yml +8 -8
  372. data/test/fixtures/sponsors.yml +12 -12
  373. data/test/fixtures/string_key_objects.yml +7 -7
  374. data/test/fixtures/subscribers.yml +10 -10
  375. data/test/fixtures/subscriptions.yml +12 -12
  376. data/test/fixtures/taggings.yml +78 -78
  377. data/test/fixtures/tags.yml +11 -11
  378. data/test/fixtures/tasks.yml +7 -7
  379. data/test/fixtures/teapots.yml +3 -3
  380. data/test/fixtures/to_be_linked/accounts.yml +2 -2
  381. data/test/fixtures/to_be_linked/users.yml +10 -10
  382. data/test/fixtures/topics.yml +49 -49
  383. data/test/fixtures/toys.yml +14 -14
  384. data/test/fixtures/traffic_lights.yml +9 -9
  385. data/test/fixtures/treasures.yml +10 -10
  386. data/test/fixtures/trees.yml +3 -0
  387. data/test/fixtures/uuid_children.yml +3 -3
  388. data/test/fixtures/uuid_parents.yml +2 -2
  389. data/test/fixtures/variants.yml +4 -4
  390. data/test/fixtures/vegetables.yml +19 -19
  391. data/test/fixtures/vertices.yml +3 -3
  392. data/test/fixtures/warehouse_things.yml +2 -2
  393. data/test/fixtures/zines.yml +5 -5
  394. data/test/ibm_db_test.rb +24 -24
  395. data/test/migrations/10_urban/9_add_expressions.rb +11 -11
  396. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -15
  397. data/test/migrations/magic/1_currencies_have_symbols.rb +12 -12
  398. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -9
  399. data/test/migrations/missing/1_people_have_last_names.rb +9 -9
  400. data/test/migrations/missing/3_we_need_reminders.rb +12 -12
  401. data/test/migrations/missing/4_innocent_jointable.rb +12 -12
  402. data/test/migrations/rename/1_we_need_things.rb +11 -11
  403. data/test/migrations/rename/2_rename_things.rb +9 -9
  404. data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -9
  405. data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -9
  406. data/test/migrations/to_copy2/1_create_articles.rb +7 -7
  407. data/test/migrations/to_copy2/2_create_comments.rb +7 -7
  408. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -9
  409. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -9
  410. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -9
  411. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -7
  412. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -7
  413. data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -9
  414. data/test/migrations/valid/2_we_need_reminders.rb +12 -12
  415. data/test/migrations/valid/3_innocent_jointable.rb +12 -12
  416. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -9
  417. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +12 -12
  418. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +12 -12
  419. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -9
  420. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -12
  421. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -12
  422. data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -8
  423. data/test/models/admin.rb +4 -4
  424. data/test/models/admin/account.rb +2 -2
  425. data/test/models/admin/randomly_named_c1.rb +7 -3
  426. data/test/models/admin/user.rb +40 -40
  427. data/test/models/aircraft.rb +5 -4
  428. data/test/models/arunit2_model.rb +3 -3
  429. data/test/models/author.rb +209 -212
  430. data/test/models/auto_id.rb +4 -4
  431. data/test/models/autoloadable/extra_firm.rb +2 -2
  432. data/test/models/binary.rb +1 -1
  433. data/test/models/bird.rb +12 -12
  434. data/test/models/book.rb +23 -18
  435. data/test/models/boolean.rb +2 -2
  436. data/test/models/bulb.rb +52 -51
  437. data/test/models/cake_designer.rb +3 -3
  438. data/test/models/car.rb +29 -26
  439. data/test/models/carrier.rb +2 -2
  440. data/test/models/cat.rb +10 -0
  441. data/test/models/categorization.rb +19 -19
  442. data/test/models/category.rb +35 -35
  443. data/test/models/chef.rb +8 -3
  444. data/test/models/citation.rb +3 -3
  445. data/test/models/club.rb +25 -23
  446. data/test/models/college.rb +10 -10
  447. data/test/models/column.rb +3 -3
  448. data/test/models/column_name.rb +3 -3
  449. data/test/models/comment.rb +76 -64
  450. data/test/models/company.rb +230 -225
  451. data/test/models/company_in_module.rb +98 -98
  452. data/test/models/computer.rb +3 -3
  453. data/test/models/contact.rb +41 -41
  454. data/test/models/content.rb +40 -0
  455. data/test/models/contract.rb +20 -20
  456. data/test/models/country.rb +7 -7
  457. data/test/models/course.rb +6 -6
  458. data/test/models/customer.rb +83 -77
  459. data/test/models/customer_carrier.rb +14 -14
  460. data/test/models/dashboard.rb +3 -3
  461. data/test/models/default.rb +2 -2
  462. data/test/models/department.rb +4 -4
  463. data/test/models/developer.rb +274 -252
  464. data/test/models/dog.rb +5 -5
  465. data/test/models/dog_lover.rb +5 -5
  466. data/test/models/doubloon.rb +12 -12
  467. data/test/models/drink_designer.rb +3 -3
  468. data/test/models/edge.rb +5 -5
  469. data/test/models/electron.rb +5 -5
  470. data/test/models/engine.rb +4 -4
  471. data/test/models/entrant.rb +3 -3
  472. data/test/models/essay.rb +5 -5
  473. data/test/models/event.rb +2 -2
  474. data/test/models/eye.rb +37 -37
  475. data/test/models/face.rb +9 -9
  476. data/test/models/friendship.rb +6 -6
  477. data/test/models/guid.rb +1 -1
  478. data/test/models/guitar.rb +4 -0
  479. data/test/models/hotel.rb +11 -6
  480. data/test/models/image.rb +3 -3
  481. data/test/models/interest.rb +5 -5
  482. data/test/models/invoice.rb +4 -4
  483. data/test/models/item.rb +7 -7
  484. data/test/models/job.rb +7 -7
  485. data/test/models/joke.rb +7 -7
  486. data/test/models/keyboard.rb +3 -3
  487. data/test/models/legacy_thing.rb +3 -3
  488. data/test/models/lesson.rb +11 -11
  489. data/test/models/line_item.rb +3 -3
  490. data/test/models/liquid.rb +4 -4
  491. data/test/models/man.rb +11 -11
  492. data/test/models/matey.rb +4 -4
  493. data/test/models/member.rb +42 -41
  494. data/test/models/member_detail.rb +8 -7
  495. data/test/models/member_type.rb +3 -3
  496. data/test/models/membership.rb +35 -35
  497. data/test/models/mentor.rb +3 -0
  498. data/test/models/minimalistic.rb +2 -2
  499. data/test/models/minivan.rb +9 -9
  500. data/test/models/mixed_case_monkey.rb +3 -3
  501. data/test/models/mocktail_designer.rb +2 -0
  502. data/test/models/molecule.rb +6 -6
  503. data/test/models/movie.rb +5 -5
  504. data/test/models/node.rb +5 -0
  505. data/test/models/non_primary_key.rb +2 -0
  506. data/test/models/notification.rb +3 -0
  507. data/test/models/order.rb +4 -4
  508. data/test/models/organization.rb +14 -14
  509. data/test/models/other_dog.rb +5 -0
  510. data/test/models/owner.rb +37 -34
  511. data/test/models/parrot.rb +28 -29
  512. data/test/models/person.rb +142 -143
  513. data/test/models/personal_legacy_thing.rb +4 -4
  514. data/test/models/pet.rb +18 -15
  515. data/test/models/pet_treasure.rb +6 -0
  516. data/test/models/pirate.rb +92 -92
  517. data/test/models/possession.rb +3 -3
  518. data/test/models/post.rb +273 -264
  519. data/test/models/price_estimate.rb +4 -4
  520. data/test/models/professor.rb +5 -5
  521. data/test/models/project.rb +40 -29
  522. data/test/models/publisher.rb +2 -2
  523. data/test/models/publisher/article.rb +4 -4
  524. data/test/models/publisher/magazine.rb +3 -3
  525. data/test/models/randomly_named_c1.rb +3 -3
  526. data/test/models/rating.rb +4 -4
  527. data/test/models/reader.rb +23 -23
  528. data/test/models/recipe.rb +3 -0
  529. data/test/models/record.rb +2 -2
  530. data/test/models/reference.rb +22 -22
  531. data/test/models/reply.rb +61 -61
  532. data/test/models/ship.rb +39 -33
  533. data/test/models/ship_part.rb +7 -7
  534. data/test/models/shop.rb +17 -17
  535. data/test/models/shop_account.rb +6 -6
  536. data/test/models/speedometer.rb +6 -6
  537. data/test/models/sponsor.rb +7 -7
  538. data/test/models/string_key_object.rb +3 -3
  539. data/test/models/student.rb +4 -4
  540. data/test/models/subject.rb +16 -16
  541. data/test/models/subscriber.rb +8 -8
  542. data/test/models/subscription.rb +4 -4
  543. data/test/models/tag.rb +13 -7
  544. data/test/models/tagging.rb +13 -13
  545. data/test/models/task.rb +5 -5
  546. data/test/models/topic.rb +118 -124
  547. data/test/models/toy.rb +6 -6
  548. data/test/models/traffic_light.rb +4 -4
  549. data/test/models/treasure.rb +14 -14
  550. data/test/models/treaty.rb +7 -7
  551. data/test/models/tree.rb +3 -0
  552. data/test/models/tuning_peg.rb +4 -0
  553. data/test/models/tyre.rb +11 -11
  554. data/test/models/user.rb +14 -0
  555. data/test/models/uuid_child.rb +3 -3
  556. data/test/models/uuid_item.rb +6 -0
  557. data/test/models/uuid_parent.rb +3 -3
  558. data/test/models/vegetables.rb +24 -24
  559. data/test/models/vehicle.rb +6 -6
  560. data/test/models/vertex.rb +9 -9
  561. data/test/models/warehouse_thing.rb +5 -5
  562. data/test/models/wheel.rb +3 -3
  563. data/test/models/without_table.rb +3 -3
  564. data/test/models/zine.rb +3 -3
  565. data/test/schema/mysql2_specific_schema.rb +68 -58
  566. data/test/schema/oracle_specific_schema.rb +40 -43
  567. data/test/schema/postgresql_specific_schema.rb +114 -202
  568. data/test/schema/schema.rb +1057 -938
  569. data/test/schema/schema.rb.original +1057 -0
  570. data/test/schema/sqlite_specific_schema.rb +18 -22
  571. data/test/support/config.rb +43 -43
  572. data/test/support/connection.rb +23 -22
  573. data/test/support/connection_helper.rb +14 -14
  574. data/test/support/ddl_helper.rb +8 -8
  575. data/test/support/schema_dumping_helper.rb +20 -20
  576. data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -0
  577. data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -0
  578. metadata +146 -30
  579. data/lib/mswin32/rb19x/ibm_db.so +0 -0
  580. data/lib/mswin32/rb21x/i386/ibm_db.so +0 -0
  581. data/lib/mswin32/rb22x/i386/ibm_db.so +0 -0
  582. data/lib/mswin32/rb23x/i386/ibm_db.so +0 -0
  583. data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +0 -26
  584. data/test/cases/attribute_methods/serialization_test.rb +0 -29
  585. data/test/cases/migration/change_schema_test - Copy.rb +0 -448
  586. data/test/cases/migration/foreign_key_test - Changed.rb +0 -325
  587. data/test/cases/migration/table_and_index_test.rb +0 -24
  588. data/test/cases/relation/where_test2.rb +0 -36
  589. data/test/cases/type/decimal_test.rb +0 -51
  590. data/test/cases/type/unsigned_integer_test.rb +0 -18
  591. data/test/cases/xml_serialization_test.rb +0 -457
  592. data/test/fixtures/naked/csv/accounts.csv +0 -1
  593. data/test/schema/mysql_specific_schema.rb +0 -70
@@ -1,82 +1,87 @@
1
- require "cases/helper"
2
- require 'models/post'
3
- require 'models/comment'
4
- require 'models/project'
5
- require 'models/developer'
6
- require 'models/computer'
7
- require 'models/company_in_module'
8
-
9
- class AssociationsExtensionsTest < ActiveRecord::TestCase
10
- fixtures :projects, :developers, :developers_projects, :comments, :posts
11
-
12
- def test_extension_on_has_many
13
- assert_equal comments(:more_greetings), posts(:welcome).comments.find_most_recent
14
- end
15
-
16
- def test_extension_on_habtm
17
- assert_equal projects(:action_controller), developers(:david).projects.find_most_recent
18
- end
19
-
20
- def test_named_extension_on_habtm
21
- assert_equal projects(:action_controller), developers(:david).projects_extended_by_name.find_most_recent
22
- end
23
-
24
- def test_named_two_extensions_on_habtm
25
- assert_equal projects(:action_controller), developers(:david).projects_extended_by_name_twice.find_most_recent
26
- assert_equal projects(:active_record), developers(:david).projects_extended_by_name_twice.find_least_recent
27
- end
28
-
29
- def test_named_extension_and_block_on_habtm
30
- assert_equal projects(:action_controller), developers(:david).projects_extended_by_name_and_block.find_most_recent
31
- assert_equal projects(:active_record), developers(:david).projects_extended_by_name_and_block.find_least_recent
32
- end
33
-
34
- def test_extension_with_scopes
35
- assert_equal comments(:greetings), posts(:welcome).comments.offset(1).find_most_recent
36
- assert_equal comments(:greetings), posts(:welcome).comments.not_again.find_most_recent
37
- end
38
-
39
- def test_marshalling_extensions
40
- david = developers(:david)
41
- assert_equal projects(:action_controller), david.projects.find_most_recent
42
-
43
- marshalled = Marshal.dump(david)
44
-
45
- # Marshaling an association shouldn't make it unusable by wiping its reflection.
46
- assert_not_nil david.association(:projects).reflection
47
-
48
- david_too = Marshal.load(marshalled)
49
- assert_equal projects(:action_controller), david_too.projects.find_most_recent
50
- end
51
-
52
- def test_marshalling_named_extensions
53
- david = developers(:david)
54
- assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent
55
-
56
- marshalled = Marshal.dump(david)
57
- david = Marshal.load(marshalled)
58
-
59
- assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent
60
- end
61
-
62
- def test_extension_name
63
- extend!(Developer)
64
- extend!(MyApplication::Business::Developer)
65
-
66
- assert Object.const_get 'DeveloperAssociationNameAssociationExtension'
67
- assert MyApplication::Business.const_get 'DeveloperAssociationNameAssociationExtension'
68
- end
69
-
70
- def test_proxy_association_after_scoped
71
- post = posts(:welcome)
72
- assert_equal post.association(:comments), post.comments.the_association
73
- assert_equal post.association(:comments), post.comments.where('1=1').the_association
74
- end
75
-
76
- private
77
-
78
- def extend!(model)
79
- builder = ActiveRecord::Associations::Builder::HasMany.new(model, :association_name, nil, {}) { }
80
- builder.define_extensions(model)
81
- end
82
- end
1
+ require "cases/helper"
2
+ require 'models/post'
3
+ require 'models/comment'
4
+ require 'models/project'
5
+ require 'models/developer'
6
+ require 'models/computer'
7
+ require 'models/company_in_module'
8
+
9
+ class AssociationsExtensionsTest < ActiveRecord::TestCase
10
+ fixtures :projects, :developers, :developers_projects, :comments, :posts
11
+
12
+ def test_extension_on_has_many
13
+ assert_equal comments(:more_greetings), posts(:welcome).comments.find_most_recent
14
+ end
15
+
16
+ def test_extension_on_habtm
17
+ assert_equal projects(:action_controller), developers(:david).projects.find_most_recent
18
+ end
19
+
20
+ def test_named_extension_on_habtm
21
+ assert_equal projects(:action_controller), developers(:david).projects_extended_by_name.find_most_recent
22
+ end
23
+
24
+ def test_named_two_extensions_on_habtm
25
+ assert_equal projects(:action_controller), developers(:david).projects_extended_by_name_twice.find_most_recent
26
+ assert_equal projects(:active_record), developers(:david).projects_extended_by_name_twice.find_least_recent
27
+ end
28
+
29
+ def test_named_extension_and_block_on_habtm
30
+ assert_equal projects(:action_controller), developers(:david).projects_extended_by_name_and_block.find_most_recent
31
+ assert_equal projects(:active_record), developers(:david).projects_extended_by_name_and_block.find_least_recent
32
+ end
33
+
34
+ def test_extension_with_scopes
35
+ assert_equal comments(:greetings), posts(:welcome).comments.offset(1).find_most_recent
36
+ assert_equal comments(:greetings), posts(:welcome).comments.not_again.find_most_recent
37
+ end
38
+
39
+ def test_marshalling_extensions
40
+ david = developers(:david)
41
+ assert_equal projects(:action_controller), david.projects.find_most_recent
42
+
43
+ marshalled = Marshal.dump(david)
44
+
45
+ # Marshaling an association shouldn't make it unusable by wiping its reflection.
46
+ assert_not_nil david.association(:projects).reflection
47
+
48
+ david_too = Marshal.load(marshalled)
49
+ assert_equal projects(:action_controller), david_too.projects.find_most_recent
50
+ end
51
+
52
+ def test_marshalling_named_extensions
53
+ david = developers(:david)
54
+ assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent
55
+
56
+ marshalled = Marshal.dump(david)
57
+ david = Marshal.load(marshalled)
58
+
59
+ assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent
60
+ end
61
+
62
+ def test_extension_name
63
+ extend!(Developer)
64
+ extend!(MyApplication::Business::Developer)
65
+
66
+ assert Object.const_get 'DeveloperAssociationNameAssociationExtension'
67
+ assert MyApplication::Business.const_get 'DeveloperAssociationNameAssociationExtension'
68
+ end
69
+
70
+ def test_proxy_association_after_scoped
71
+ post = posts(:welcome)
72
+ assert_equal post.association(:comments), post.comments.the_association
73
+ assert_equal post.association(:comments), post.comments.where('1=1').the_association
74
+ end
75
+
76
+ def test_association_with_default_scope
77
+ assert_raises OopsError do
78
+ posts(:welcome).comments.destroy_all
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def extend!(model)
85
+ ActiveRecord::Associations::Builder::HasMany.define_extensions(model, :association_name) { }
86
+ end
87
+ end
@@ -1,932 +1,1004 @@
1
- require "cases/helper"
2
- require 'models/developer'
3
- require 'models/computer'
4
- require 'models/project'
5
- require 'models/company'
6
- require 'models/course'
7
- require 'models/customer'
8
- require 'models/order'
9
- require 'models/categorization'
10
- require 'models/category'
11
- require 'models/post'
12
- require 'models/author'
13
- require 'models/tag'
14
- require 'models/tagging'
15
- require 'models/parrot'
16
- require 'models/person'
17
- require 'models/pirate'
18
- require 'models/professor'
19
- require 'models/treasure'
20
- require 'models/price_estimate'
21
- require 'models/club'
22
- require 'models/member'
23
- require 'models/membership'
24
- require 'models/sponsor'
25
- require 'models/country'
26
- require 'models/treaty'
27
- require 'models/vertex'
28
- require 'models/publisher'
29
- require 'models/publisher/article'
30
- require 'models/publisher/magazine'
31
- require 'active_support/core_ext/string/conversions'
32
-
33
- class ProjectWithAfterCreateHook < ActiveRecord::Base
34
- self.table_name = 'projects'
35
- has_and_belongs_to_many :developers,
36
- :class_name => "DeveloperForProjectWithAfterCreateHook",
37
- :join_table => "developers_projects",
38
- :foreign_key => "project_id",
39
- :association_foreign_key => "developer_id"
40
-
41
- after_create :add_david
42
-
43
- def add_david
44
- david = DeveloperForProjectWithAfterCreateHook.find_by_name('David')
45
- david.projects << self
46
- end
47
- end
48
-
49
- class DeveloperForProjectWithAfterCreateHook < ActiveRecord::Base
50
- self.table_name = 'developers'
51
- has_and_belongs_to_many :projects,
52
- :class_name => "ProjectWithAfterCreateHook",
53
- :join_table => "developers_projects",
54
- :association_foreign_key => "project_id",
55
- :foreign_key => "developer_id"
56
- end
57
-
58
- class ProjectWithSymbolsForKeys < ActiveRecord::Base
59
- self.table_name = 'projects'
60
- has_and_belongs_to_many :developers,
61
- :class_name => "DeveloperWithSymbolsForKeys",
62
- :join_table => :developers_projects,
63
- :foreign_key => :project_id,
64
- :association_foreign_key => "developer_id"
65
- end
66
-
67
- class DeveloperWithSymbolsForKeys < ActiveRecord::Base
68
- self.table_name = 'developers'
69
- has_and_belongs_to_many :projects,
70
- :class_name => "ProjectWithSymbolsForKeys",
71
- :join_table => :developers_projects,
72
- :association_foreign_key => :project_id,
73
- :foreign_key => "developer_id"
74
- end
75
-
76
- class SubDeveloper < Developer
77
- self.table_name = 'developers'
78
- has_and_belongs_to_many :special_projects,
79
- :join_table => 'developers_projects',
80
- :foreign_key => "project_id",
81
- :association_foreign_key => "developer_id"
82
- end
83
-
84
- class DeveloperWithSymbolClassName < Developer
85
- has_and_belongs_to_many :projects, class_name: :ProjectWithSymbolsForKeys
86
- end
87
-
88
- class DeveloperWithExtendOption < Developer
89
- module NamedExtension
90
- def category
91
- 'sns'
92
- end
93
- end
94
-
95
- has_and_belongs_to_many :projects, extend: NamedExtension
96
- end
97
-
98
- class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
99
- fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
100
- :parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings, :computers
101
-
102
- def setup_data_for_habtm_case
103
- ActiveRecord::Base.connection.execute('delete from countries_treaties')
104
-
105
- country = Country.new(:name => 'India')
106
- country.country_id = 'c1'
107
- country.save!
108
-
109
- treaty = Treaty.new(:name => 'peace')
110
- treaty.treaty_id = 't1'
111
- country.treaties << treaty
112
- end
113
-
114
- def test_marshal_dump
115
- post = posts :welcome
116
- preloaded = Post.includes(:categories).find post.id
117
- assert_equal preloaded, Marshal.load(Marshal.dump(preloaded))
118
- end
119
-
120
- def test_should_property_quote_string_primary_keys
121
- setup_data_for_habtm_case
122
-
123
- con = ActiveRecord::Base.connection
124
- sql = 'select * from countries_treaties'
125
- record = con.select_rows(sql).last
126
- assert_equal 'c1', record[0]
127
- assert_equal 't1', record[1]
128
- end
129
-
130
- def test_proper_usage_of_primary_keys_and_join_table
131
- setup_data_for_habtm_case
132
-
133
- assert_equal 'country_id', Country.primary_key
134
- assert_equal 'treaty_id', Treaty.primary_key
135
-
136
- country = Country.first
137
- assert_equal 1, country.treaties.count
138
- end
139
-
140
- def test_has_and_belongs_to_many
141
- david = Developer.find(1)
142
-
143
- assert !david.projects.empty?
144
- assert_equal 2, david.projects.size
145
-
146
- active_record = Project.find(1)
147
- assert !active_record.developers.empty?
148
- assert_equal 3, active_record.developers.size
149
- assert active_record.developers.include?(david)
150
- end
151
-
152
- def test_adding_single
153
- jamis = Developer.find(2)
154
- jamis.projects.reload # causing the collection to load
155
- action_controller = Project.find(2)
156
- assert_equal 1, jamis.projects.size
157
- assert_equal 1, action_controller.developers.size
158
-
159
- jamis.projects << action_controller
160
-
161
- assert_equal 2, jamis.projects.size
162
- assert_equal 2, jamis.projects(true).size
163
- assert_equal 2, action_controller.developers(true).size
164
- end
165
-
166
- def test_adding_type_mismatch
167
- jamis = Developer.find(2)
168
- assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << nil }
169
- assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << 1 }
170
- end
171
-
172
- def test_adding_from_the_project
173
- jamis = Developer.find(2)
174
- action_controller = Project.find(2)
175
- action_controller.developers.reload
176
- assert_equal 1, jamis.projects.size
177
- assert_equal 1, action_controller.developers.size
178
-
179
- action_controller.developers << jamis
180
-
181
- assert_equal 2, jamis.projects(true).size
182
- assert_equal 2, action_controller.developers.size
183
- assert_equal 2, action_controller.developers(true).size
184
- end
185
-
186
- def test_adding_from_the_project_fixed_timestamp
187
- jamis = Developer.find(2)
188
- action_controller = Project.find(2)
189
- action_controller.developers.reload
190
- assert_equal 1, jamis.projects.size
191
- assert_equal 1, action_controller.developers.size
192
- updated_at = jamis.updated_at
193
-
194
- action_controller.developers << jamis
195
-
196
- assert_equal updated_at, jamis.updated_at
197
- assert_equal 2, jamis.projects(true).size
198
- assert_equal 2, action_controller.developers.size
199
- assert_equal 2, action_controller.developers(true).size
200
- end
201
-
202
- def test_adding_multiple
203
- aredridel = Developer.new("name" => "Aredridel")
204
- aredridel.save
205
- aredridel.projects.reload
206
- aredridel.projects.push(Project.find(1), Project.find(2))
207
- assert_equal 2, aredridel.projects.size
208
- assert_equal 2, aredridel.projects(true).size
209
- end
210
-
211
- def test_adding_a_collection
212
- aredridel = Developer.new("name" => "Aredridel")
213
- aredridel.save
214
- aredridel.projects.reload
215
- aredridel.projects.concat([Project.find(1), Project.find(2)])
216
- assert_equal 2, aredridel.projects.size
217
- assert_equal 2, aredridel.projects(true).size
218
- end
219
-
220
- def test_habtm_adding_before_save
221
- no_of_devels = Developer.count
222
- no_of_projects = Project.count
223
- aredridel = Developer.new("name" => "Aredridel")
224
- aredridel.projects.concat([Project.find(1), p = Project.new("name" => "Projekt")])
225
- assert !aredridel.persisted?
226
- assert !p.persisted?
227
- assert aredridel.save
228
- assert aredridel.persisted?
229
- assert_equal no_of_devels+1, Developer.count
230
- assert_equal no_of_projects+1, Project.count
231
- assert_equal 2, aredridel.projects.size
232
- assert_equal 2, aredridel.projects(true).size
233
- end
234
-
235
- def test_habtm_saving_multiple_relationships
236
- new_project = Project.new("name" => "Grimetime")
237
- amount_of_developers = 4
238
- developers = (0...amount_of_developers).collect {|i| Developer.create(:name => "JME #{i}") }.reverse
239
-
240
- new_project.developer_ids = [developers[0].id, developers[1].id]
241
- new_project.developers_with_callback_ids = [developers[2].id, developers[3].id]
242
- assert new_project.save
243
-
244
- new_project.reload
245
- assert_equal amount_of_developers, new_project.developers.size
246
- assert_equal developers, new_project.developers
247
- end
248
-
249
- def test_habtm_unique_order_preserved
250
- assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).non_unique_developers
251
- assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).developers
252
- end
253
-
254
- def test_habtm_collection_size_from_build
255
- devel = Developer.create("name" => "Fred Wu")
256
- devel.projects << Project.create("name" => "Grimetime")
257
- devel.projects.build
258
-
259
- assert_equal 2, devel.projects.size
260
- end
261
-
262
- def test_habtm_collection_size_from_params
263
- devel = Developer.new({
264
- projects_attributes: {
265
- '0' => {}
266
- }
267
- })
268
-
269
- assert_equal 1, devel.projects.size
270
- end
271
-
272
- def test_build
273
- devel = Developer.find(1)
274
- proj = assert_no_queries(ignore_none: false) { devel.projects.build("name" => "Projekt") }
275
- assert !devel.projects.loaded?
276
-
277
- assert_equal devel.projects.last, proj
278
- assert devel.projects.loaded?
279
-
280
- assert !proj.persisted?
281
- devel.save
282
- assert proj.persisted?
283
- assert_equal devel.projects.last, proj
284
- assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
285
- end
286
-
287
- def test_new_aliased_to_build
288
- devel = Developer.find(1)
289
- proj = assert_no_queries(ignore_none: false) { devel.projects.new("name" => "Projekt") }
290
- assert !devel.projects.loaded?
291
-
292
- assert_equal devel.projects.last, proj
293
- assert devel.projects.loaded?
294
-
295
- assert !proj.persisted?
296
- devel.save
297
- assert proj.persisted?
298
- assert_equal devel.projects.last, proj
299
- assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
300
- end
301
-
302
- def test_build_by_new_record
303
- devel = Developer.new(:name => "Marcel", :salary => 75000)
304
- devel.projects.build(:name => "Make bed")
305
- proj2 = devel.projects.build(:name => "Lie in it")
306
- assert_equal devel.projects.last, proj2
307
- assert !proj2.persisted?
308
- devel.save
309
- assert devel.persisted?
310
- assert proj2.persisted?
311
- assert_equal devel.projects.last, proj2
312
- assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
313
- end
314
-
315
- def test_create
316
- devel = Developer.find(1)
317
- proj = devel.projects.create("name" => "Projekt")
318
- assert !devel.projects.loaded?
319
-
320
- assert_equal devel.projects.last, proj
321
- assert !devel.projects.loaded?
322
-
323
- assert proj.persisted?
324
- assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
325
- end
326
-
327
- def test_create_by_new_record
328
- devel = Developer.new(:name => "Marcel", :salary => 75000)
329
- devel.projects.build(:name => "Make bed")
330
- proj2 = devel.projects.build(:name => "Lie in it")
331
- assert_equal devel.projects.last, proj2
332
- assert !proj2.persisted?
333
- devel.save
334
- assert devel.persisted?
335
- assert proj2.persisted?
336
- assert_equal devel.projects.last, proj2
337
- assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
338
- end
339
-
340
- def test_creation_respects_hash_condition
341
- # in Oracle '' is saved as null therefore need to save ' ' in not null column
342
- post = categories(:general).post_with_conditions.build(:body => ' ')
343
-
344
- assert post.save
345
- assert_equal 'Yet Another Testing Title', post.title
346
-
347
- # in Oracle '' is saved as null therefore need to save ' ' in not null column
348
- another_post = categories(:general).post_with_conditions.create(:body => ' ')
349
-
350
- assert another_post.persisted?
351
- assert_equal 'Yet Another Testing Title', another_post.title
352
- end
353
-
354
- def test_uniq_after_the_fact
355
- dev = developers(:jamis)
356
- dev.projects << projects(:active_record)
357
- dev.projects << projects(:active_record)
358
-
359
- assert_equal 3, dev.projects.size
360
- assert_equal 1, dev.projects.distinct.size
361
- end
362
-
363
- def test_uniq_before_the_fact
364
- projects(:active_record).developers << developers(:jamis)
365
- projects(:active_record).developers << developers(:david)
366
- assert_equal 3, projects(:active_record, :reload).developers.size
367
- end
368
-
369
- def test_uniq_option_prevents_duplicate_push
370
- project = projects(:active_record)
371
- project.developers << developers(:jamis)
372
- project.developers << developers(:david)
373
- assert_equal 3, project.developers.size
374
-
375
- project.developers << developers(:david)
376
- project.developers << developers(:jamis)
377
- assert_equal 3, project.developers.size
378
- end
379
-
380
- def test_uniq_when_association_already_loaded
381
- project = projects(:active_record)
382
- project.developers << [ developers(:jamis), developers(:david), developers(:jamis), developers(:david) ]
383
- assert_equal 3, Project.includes(:developers).find(project.id).developers.size
384
- end
385
-
386
- def test_deleting
387
- david = Developer.find(1)
388
- active_record = Project.find(1)
389
- david.projects.reload
390
- assert_equal 2, david.projects.size
391
- assert_equal 3, active_record.developers.size
392
-
393
- david.projects.delete(active_record)
394
-
395
- assert_equal 1, david.projects.size
396
- assert_equal 1, david.projects(true).size
397
- assert_equal 2, active_record.developers(true).size
398
- end
399
-
400
- def test_deleting_array
401
- david = Developer.find(1)
402
- david.projects.reload
403
- david.projects.delete(Project.all.to_a)
404
- assert_equal 0, david.projects.size
405
- assert_equal 0, david.projects(true).size
406
- end
407
-
408
- def test_deleting_all
409
- david = Developer.find(1)
410
- david.projects.reload
411
- david.projects.clear
412
- assert_equal 0, david.projects.size
413
- assert_equal 0, david.projects(true).size
414
- end
415
-
416
- def test_removing_associations_on_destroy
417
- david = DeveloperWithBeforeDestroyRaise.find(1)
418
- assert !david.projects.empty?
419
- david.destroy
420
- assert david.projects.empty?
421
- assert DeveloperWithBeforeDestroyRaise.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = 1").empty?
422
- end
423
-
424
- def test_destroying
425
- david = Developer.find(1)
426
- project = Project.find(1)
427
- david.projects.reload
428
- assert_equal 2, david.projects.size
429
- assert_equal 3, project.developers.size
430
-
431
- assert_no_difference "Project.count" do
432
- david.projects.destroy(project)
433
- end
434
-
435
- join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id} AND project_id = #{project.id}")
436
- assert join_records.empty?
437
-
438
- assert_equal 1, david.reload.projects.size
439
- assert_equal 1, david.projects(true).size
440
- end
441
-
442
- def test_destroying_many
443
- david = Developer.find(1)
444
- david.projects.reload
445
- projects = Project.all.to_a
446
-
447
- assert_no_difference "Project.count" do
448
- david.projects.destroy(*projects)
449
- end
450
-
451
- join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id}")
452
- assert join_records.empty?
453
-
454
- assert_equal 0, david.reload.projects.size
455
- assert_equal 0, david.projects(true).size
456
- end
457
-
458
- def test_destroy_all
459
- david = Developer.find(1)
460
- david.projects.reload
461
- assert !david.projects.empty?
462
-
463
- assert_no_difference "Project.count" do
464
- david.projects.destroy_all
465
- end
466
-
467
- join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id}")
468
- assert join_records.empty?
469
-
470
- assert david.projects.empty?
471
- assert david.projects(true).empty?
472
- end
473
-
474
- def test_destroy_associations_destroys_multiple_associations
475
- george = parrots(:george)
476
- assert !george.pirates.empty?
477
- assert !george.treasures.empty?
478
-
479
- assert_no_difference "Pirate.count" do
480
- assert_no_difference "Treasure.count" do
481
- george.destroy_associations
482
- end
483
- end
484
-
485
- join_records = Parrot.connection.select_all("SELECT * FROM parrots_pirates WHERE parrot_id = #{george.id}")
486
- assert join_records.empty?
487
- assert george.pirates(true).empty?
488
-
489
- join_records = Parrot.connection.select_all("SELECT * FROM parrots_treasures WHERE parrot_id = #{george.id}")
490
- assert join_records.empty?
491
- assert george.treasures(true).empty?
492
- end
493
-
494
- def test_associations_with_conditions
495
- assert_equal 3, projects(:active_record).developers.size
496
- assert_equal 1, projects(:active_record).developers_named_david.size
497
- assert_equal 1, projects(:active_record).developers_named_david_with_hash_conditions.size
498
-
499
- assert_equal developers(:david), projects(:active_record).developers_named_david.find(developers(:david).id)
500
- assert_equal developers(:david), projects(:active_record).developers_named_david_with_hash_conditions.find(developers(:david).id)
501
- assert_equal developers(:david), projects(:active_record).salaried_developers.find(developers(:david).id)
502
-
503
- projects(:active_record).developers_named_david.clear
504
- assert_equal 2, projects(:active_record, :reload).developers.size
505
- end
506
-
507
- def test_find_in_association
508
- # Using sql
509
- assert_equal developers(:david), projects(:active_record).developers.find(developers(:david).id), "SQL find"
510
-
511
- # Using ruby
512
- active_record = projects(:active_record)
513
- active_record.developers.reload
514
- assert_equal developers(:david), active_record.developers.find(developers(:david).id), "Ruby find"
515
- end
516
-
517
- def test_include_uses_array_include_after_loaded
518
- project = projects(:active_record)
519
- project.developers.load_target
520
-
521
- developer = project.developers.first
522
-
523
- assert_no_queries(ignore_none: false) do
524
- assert project.developers.loaded?
525
- assert project.developers.include?(developer)
526
- end
527
- end
528
-
529
- def test_include_checks_if_record_exists_if_target_not_loaded
530
- project = projects(:active_record)
531
- developer = project.developers.first
532
-
533
- project.reload
534
- assert ! project.developers.loaded?
535
- assert_queries(1) do
536
- assert project.developers.include?(developer)
537
- end
538
- assert ! project.developers.loaded?
539
- end
540
-
541
- def test_include_returns_false_for_non_matching_record_to_verify_scoping
542
- project = projects(:active_record)
543
- developer = Developer.create :name => "Bryan", :salary => 50_000
544
-
545
- assert ! project.developers.loaded?
546
- assert ! project.developers.include?(developer)
547
- end
548
-
549
- def test_find_with_merged_options
550
- assert_equal 1, projects(:active_record).limited_developers.size
551
- assert_equal 1, projects(:active_record).limited_developers.to_a.size
552
- assert_equal 3, projects(:active_record).limited_developers.limit(nil).to_a.size
553
- end
554
-
555
- def test_dynamic_find_should_respect_association_order
556
- # Developers are ordered 'name DESC, id DESC'
557
- high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
558
-
559
- assert_equal high_id_jamis, projects(:active_record).developers.merge(:where => "name = 'Jamis'").first
560
- assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis')
561
- end
562
-
563
- def test_find_should_append_to_association_order
564
- ordered_developers = projects(:active_record).developers.order('projects.id')
565
- assert_equal ['developers.name desc, developers.id desc', 'projects.id'], ordered_developers.order_values
566
- end
567
-
568
- def test_dynamic_find_all_should_respect_readonly_access
569
- 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? }
571
- end
572
-
573
- def test_new_with_values_in_collection
574
- jamis = DeveloperForProjectWithAfterCreateHook.find_by_name('Jamis')
575
- david = DeveloperForProjectWithAfterCreateHook.find_by_name('David')
576
- project = ProjectWithAfterCreateHook.new(:name => "Cooking with Bertie")
577
- project.developers << jamis
578
- project.save!
579
- project.reload
580
-
581
- assert project.developers.include?(jamis)
582
- assert project.developers.include?(david)
583
- end
584
-
585
- def test_find_in_association_with_options
586
- developers = projects(:active_record).developers.to_a
587
- assert_equal 3, developers.size
588
-
589
- assert_equal developers(:poor_jamis), projects(:active_record).developers.where("salary < 10000").first
590
- end
591
-
592
- def test_association_with_extend_option
593
- eponine = DeveloperWithExtendOption.create(name: 'Eponine')
594
- assert_equal 'sns', eponine.projects.category
595
- end
596
-
597
- def test_replace_with_less
598
- david = developers(:david)
599
- david.projects = [projects(:action_controller)]
600
- assert david.save
601
- assert_equal 1, david.projects.length
602
- end
603
-
604
- def test_replace_with_new
605
- david = developers(:david)
606
- david.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")]
607
- david.save
608
- assert_equal 2, david.projects.length
609
- assert !david.projects.include?(projects(:active_record))
610
- end
611
-
612
- def test_replace_on_new_object
613
- new_developer = Developer.new("name" => "Matz")
614
- new_developer.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")]
615
- new_developer.save
616
- assert_equal 2, new_developer.projects.length
617
- end
618
-
619
- def test_consider_type
620
- developer = Developer.first
621
- special_project = SpecialProject.create("name" => "Special Project")
622
-
623
- other_project = developer.projects.first
624
- developer.special_projects << special_project
625
- developer.reload
626
-
627
- assert developer.projects.include?(special_project)
628
- assert developer.special_projects.include?(special_project)
629
- assert !developer.special_projects.include?(other_project)
630
- end
631
-
632
- def test_symbol_join_table
633
- developer = Developer.first
634
- sp = developer.sym_special_projects.create("name" => "omg")
635
- developer.reload
636
- assert_includes developer.sym_special_projects, sp
637
- end
638
-
639
- def test_update_attributes_after_push_without_duplicate_join_table_rows
640
- developer = Developer.new("name" => "Kano")
641
- project = SpecialProject.create("name" => "Special Project")
642
- assert developer.save
643
- developer.projects << project
644
- developer.update_columns("name" => "Bruza")
645
- assert_equal 1, Developer.connection.select_value(<<-end_sql).to_i
646
- SELECT count(*) FROM developers_projects
647
- WHERE project_id = #{project.id}
648
- AND developer_id = #{developer.id}
649
- end_sql
650
- end
651
-
652
- def test_updating_attributes_on_non_rich_associations
653
- welcome = categories(:technology).posts.first
654
- welcome.title = "Something else"
655
- assert welcome.save!
656
- end
657
-
658
- def test_habtm_respects_select
659
- categories(:technology).select_testing_posts(true).each do |o|
660
- assert_respond_to o, :correctness_marker
661
- end
662
- assert_respond_to categories(:technology).select_testing_posts.first, :correctness_marker
663
- end
664
-
665
- def test_habtm_selects_all_columns_by_default
666
- assert_equal Project.column_names.sort, developers(:david).projects.first.attributes.keys.sort
667
- end
668
-
669
- def test_habtm_respects_select_query_method
670
- assert_equal ['id'], developers(:david).projects.select(:id).first.attributes.keys
671
- end
672
-
673
- def test_join_table_alias
674
- # FIXME: `references` has no impact on the aliases generated for the join
675
- # query. The fact that we pass `:developers_projects_join` to `references`
676
- # and that the SQL string contains `developers_projects_join` is merely a
677
- # coincidence.
678
- assert_equal(
679
- 3,
680
- Developer.references(:developers_projects_join).merge(
681
- :includes => {:projects => :developers},
682
- :where => 'projects_developers_projects_join.joined_on IS NOT NULL'
683
- ).to_a.size
684
- )
685
- end
686
-
687
- def test_join_with_group
688
- # FIXME: `references` has no impact on the aliases generated for the join
689
- # query. The fact that we pass `:developers_projects_join` to `references`
690
- # and that the SQL string contains `developers_projects_join` is merely a
691
- # coincidence.
692
- group = Developer.columns.inject([]) do |g, c|
693
- g << "developers.#{c.name}"
694
- g << "developers_projects_2.#{c.name}"
695
- end
696
- Project.columns.each { |c| group << "projects.#{c.name}" }
697
-
698
- assert_equal(
699
- 3,
700
- Developer.references(:developers_projects_join).merge(
701
- :includes => {:projects => :developers}, :where => 'projects_developers_projects_join.joined_on IS NOT NULL',
702
- :group => group.join(",")
703
- ).to_a.size
704
- )
705
- end
706
-
707
- def test_find_grouped
708
- all_posts_from_category1 = Post.all.merge!(:where => "category_id = 1", :joins => :categories).to_a
709
- grouped_posts_of_category1 = Post.all.merge!(:where => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories).to_a
710
- assert_equal 5, all_posts_from_category1.size
711
- assert_equal 2, grouped_posts_of_category1.size
712
- end
713
-
714
- def test_find_scoped_grouped
715
- assert_equal 5, categories(:general).posts_grouped_by_title.to_a.size
716
- assert_equal 1, categories(:technology).posts_grouped_by_title.to_a.size
717
- end
718
-
719
- def test_find_scoped_grouped_having
720
- assert_equal 2, projects(:active_record).well_payed_salary_groups.to_a.size
721
- assert projects(:active_record).well_payed_salary_groups.all? { |g| g.salary > 10000 }
722
- end
723
-
724
- def test_get_ids
725
- assert_equal projects(:active_record, :action_controller).map(&:id).sort, developers(:david).project_ids.sort
726
- assert_equal [projects(:active_record).id], developers(:jamis).project_ids
727
- end
728
-
729
- def test_get_ids_for_loaded_associations
730
- developer = developers(:david)
731
- developer.projects(true)
732
- assert_queries(0) do
733
- developer.project_ids
734
- developer.project_ids
735
- end
736
- end
737
-
738
- def test_get_ids_for_unloaded_associations_does_not_load_them
739
- developer = developers(:david)
740
- assert !developer.projects.loaded?
741
- assert_equal projects(:active_record, :action_controller).map(&:id).sort, developer.project_ids.sort
742
- assert !developer.projects.loaded?
743
- end
744
-
745
- def test_assign_ids
746
- developer = Developer.new("name" => "Joe")
747
- developer.project_ids = projects(:active_record, :action_controller).map(&:id)
748
- developer.save
749
- developer.reload
750
- assert_equal 2, developer.projects.length
751
- assert_equal [projects(:active_record), projects(:action_controller)].map(&:id).sort, developer.project_ids.sort
752
- end
753
-
754
- def test_assign_ids_ignoring_blanks
755
- developer = Developer.new("name" => "Joe")
756
- developer.project_ids = [projects(:active_record).id, nil, projects(:action_controller).id, '']
757
- developer.save
758
- developer.reload
759
- assert_equal 2, developer.projects.length
760
- assert_equal [projects(:active_record), projects(:action_controller)].map(&:id).sort, developer.project_ids.sort
761
- end
762
-
763
- def test_scoped_find_on_through_association_doesnt_return_read_only_records
764
- tag = Post.find(1).tags.find_by_name("General")
765
-
766
- assert_nothing_raised do
767
- tag.save!
768
- end
769
- end
770
-
771
- def test_has_many_through_polymorphic_has_manys_works
772
- assert_equal [10, 20].to_set, pirates(:redbeard).treasure_estimates.map(&:price).to_set
773
- end
774
-
775
- def test_symbols_as_keys
776
- developer = DeveloperWithSymbolsForKeys.new(:name => 'David')
777
- project = ProjectWithSymbolsForKeys.new(:name => 'Rails Testing')
778
- project.developers << developer
779
- project.save!
780
-
781
- assert_equal 1, project.developers.size
782
- assert_equal 1, developer.projects.size
783
- assert_equal developer, project.developers.first
784
- assert_equal project, developer.projects.first
785
- end
786
-
787
- def test_dynamic_find_should_respect_association_include
788
- # SQL error in sort clause if :include is not included
789
- # due to Unknown column 'authors.id'
790
- assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog')
791
- end
792
-
793
- def test_count
794
- david = Developer.find(1)
795
- assert_equal 2, david.projects.count
796
- end
797
-
798
- def test_association_proxy_transaction_method_starts_transaction_in_association_class
799
- Post.expects(:transaction)
800
- Category.first.posts.transaction do
801
- # nothing
802
- end
803
- end
804
-
805
- def test_caching_of_columns
806
- david = Developer.find(1)
807
- # clear cache possibly created by other tests
808
- david.projects.reset_column_information
809
-
810
- assert_queries(:any) { david.projects.columns }
811
- assert_no_queries { david.projects.columns }
812
-
813
- ## and again to verify that reset_column_information clears the cache correctly
814
- david.projects.reset_column_information
815
-
816
- assert_queries(:any) { david.projects.columns }
817
- assert_no_queries { david.projects.columns }
818
- end
819
-
820
- def test_attributes_are_being_set_when_initialized_from_habm_association_with_where_clause
821
- new_developer = projects(:action_controller).developers.where(:name => "Marcelo").build
822
- assert_equal new_developer.name, "Marcelo"
823
- end
824
-
825
- def test_attributes_are_being_set_when_initialized_from_habm_association_with_multiple_where_clauses
826
- new_developer = projects(:action_controller).developers.where(:name => "Marcelo").where(:salary => 90_000).build
827
- assert_equal new_developer.name, "Marcelo"
828
- assert_equal new_developer.salary, 90_000
829
- end
830
-
831
- def test_include_method_in_has_and_belongs_to_many_association_should_return_true_for_instance_added_with_build
832
- project = Project.new
833
- developer = project.developers.build
834
- assert project.developers.include?(developer)
835
- end
836
-
837
- def test_destruction_does_not_error_without_primary_key
838
- redbeard = pirates(:redbeard)
839
- george = parrots(:george)
840
- redbeard.parrots << george
841
- assert_equal 2, george.pirates.count
842
- Pirate.includes(:parrots).where(parrot: redbeard.parrot).find(redbeard.id).destroy
843
- assert_equal 1, george.pirates.count
844
- assert_equal [], Pirate.where(id: redbeard.id)
845
- end
846
-
847
- def test_has_and_belongs_to_many_associations_on_new_records_use_null_relations
848
- projects = Developer.new.projects
849
- assert_no_queries(ignore_none: false) do
850
- assert_equal [], projects
851
- assert_equal [], projects.where(title: 'omg')
852
- assert_equal [], projects.pluck(:title)
853
- assert_equal 0, projects.count
854
- end
855
- end
856
-
857
- def test_association_with_validate_false_does_not_run_associated_validation_callbacks_on_create
858
- rich_person = RichPerson.new
859
-
860
- treasure = Treasure.new
861
- treasure.rich_people << rich_person
862
- treasure.valid?
863
-
864
- assert_equal 1, treasure.rich_people.size
865
- assert_nil rich_person.first_name, 'should not run associated person validation on create when validate: false'
866
- end
867
-
868
- def test_association_with_validate_false_does_not_run_associated_validation_callbacks_on_update
869
- rich_person = RichPerson.create!
870
- person_first_name = rich_person.first_name
871
- assert_not_nil person_first_name
872
-
873
- treasure = Treasure.new
874
- treasure.rich_people << rich_person
875
- treasure.valid?
876
-
877
- assert_equal 1, treasure.rich_people.size
878
- assert_equal person_first_name, rich_person.first_name, 'should not run associated person validation on update when validate: false'
879
- end
880
-
881
- def test_custom_join_table
882
- assert_equal 'edges', Vertex.reflect_on_association(:sources).join_table
883
- end
884
-
885
- def test_has_and_belongs_to_many_in_a_namespaced_model_pointing_to_a_namespaced_model
886
- magazine = Publisher::Magazine.create
887
- article = Publisher::Article.create
888
- magazine.articles << article
889
- magazine.save
890
-
891
- assert_includes magazine.articles, article
892
- end
893
-
894
- def test_has_and_belongs_to_many_in_a_namespaced_model_pointing_to_a_non_namespaced_model
895
- article = Publisher::Article.create
896
- tag = Tag.create
897
- article.tags << tag
898
- article.save
899
-
900
- assert_includes article.tags, tag
901
- end
902
-
903
- def test_redefine_habtm
904
- child = SubDeveloper.new("name" => "Aredridel")
905
- child.special_projects << SpecialProject.new("name" => "Special Project")
906
- assert child.save, 'child object should be saved'
907
- end
908
-
909
- def test_habtm_with_reflection_using_class_name_and_fixtures
910
- assert_not_nil Developer._reflections['shared_computers']
911
- # Checking the fixture for named association is important here, because it's the only way
912
- # we've been able to reproduce this bug
913
- assert_not_nil File.read(File.expand_path("../../../fixtures/developers.yml", __FILE__)).index("shared_computers")
914
- assert_equal developers(:david).shared_computers.first, computers(:laptop)
915
- end
916
-
917
- def test_with_symbol_class_name
918
- assert_nothing_raised NoMethodError do
919
- DeveloperWithSymbolClassName.new
920
- end
921
- end
922
-
923
- def test_alternate_database
924
- professor = Professor.create(name: "Plum")
925
- course = Course.create(name: "Forensics")
926
- assert_equal 0, professor.courses.count
927
- assert_nothing_raised do
928
- professor.courses << course
929
- end
930
- assert_equal 1, professor.courses.count
931
- end
932
- end
1
+ require "cases/helper"
2
+ require 'models/developer'
3
+ require 'models/computer'
4
+ require 'models/project'
5
+ require 'models/company'
6
+ require 'models/course'
7
+ require 'models/customer'
8
+ require 'models/order'
9
+ require 'models/categorization'
10
+ require 'models/category'
11
+ require 'models/post'
12
+ require 'models/author'
13
+ require 'models/tag'
14
+ require 'models/tagging'
15
+ require 'models/parrot'
16
+ require 'models/person'
17
+ require 'models/pirate'
18
+ require 'models/professor'
19
+ require 'models/treasure'
20
+ require 'models/price_estimate'
21
+ require 'models/club'
22
+ require 'models/user'
23
+ require 'models/member'
24
+ require 'models/membership'
25
+ require 'models/sponsor'
26
+ require 'models/country'
27
+ require 'models/treaty'
28
+ require 'models/vertex'
29
+ require 'models/publisher'
30
+ require 'models/publisher/article'
31
+ require 'models/publisher/magazine'
32
+ require 'active_support/core_ext/string/conversions'
33
+
34
+ class ProjectWithAfterCreateHook < ActiveRecord::Base
35
+ self.table_name = 'projects'
36
+ has_and_belongs_to_many :developers,
37
+ :class_name => "DeveloperForProjectWithAfterCreateHook",
38
+ :join_table => "developers_projects",
39
+ :foreign_key => "project_id",
40
+ :association_foreign_key => "developer_id"
41
+
42
+ after_create :add_david
43
+
44
+ def add_david
45
+ david = DeveloperForProjectWithAfterCreateHook.find_by_name('David')
46
+ david.projects << self
47
+ end
48
+ end
49
+
50
+ class DeveloperForProjectWithAfterCreateHook < ActiveRecord::Base
51
+ self.table_name = 'developers'
52
+ has_and_belongs_to_many :projects,
53
+ :class_name => "ProjectWithAfterCreateHook",
54
+ :join_table => "developers_projects",
55
+ :association_foreign_key => "project_id",
56
+ :foreign_key => "developer_id"
57
+ end
58
+
59
+ class ProjectWithSymbolsForKeys < ActiveRecord::Base
60
+ self.table_name = 'projects'
61
+ has_and_belongs_to_many :developers,
62
+ :class_name => "DeveloperWithSymbolsForKeys",
63
+ :join_table => :developers_projects,
64
+ :foreign_key => :project_id,
65
+ :association_foreign_key => "developer_id"
66
+ end
67
+
68
+ class DeveloperWithSymbolsForKeys < ActiveRecord::Base
69
+ self.table_name = 'developers'
70
+ has_and_belongs_to_many :projects,
71
+ :class_name => "ProjectWithSymbolsForKeys",
72
+ :join_table => :developers_projects,
73
+ :association_foreign_key => :project_id,
74
+ :foreign_key => "developer_id"
75
+ end
76
+
77
+ class SubDeveloper < Developer
78
+ self.table_name = 'developers'
79
+ has_and_belongs_to_many :special_projects,
80
+ :join_table => 'developers_projects',
81
+ :foreign_key => "project_id",
82
+ :association_foreign_key => "developer_id"
83
+ end
84
+
85
+ class DeveloperWithSymbolClassName < Developer
86
+ has_and_belongs_to_many :projects, class_name: :ProjectWithSymbolsForKeys
87
+ end
88
+
89
+ class DeveloperWithExtendOption < Developer
90
+ module NamedExtension
91
+ def category
92
+ 'sns'
93
+ end
94
+ end
95
+
96
+ has_and_belongs_to_many :projects, extend: NamedExtension
97
+ end
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
+
108
+ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
109
+ fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
110
+ :parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings, :computers
111
+
112
+ def setup_data_for_habtm_case
113
+ ActiveRecord::Base.connection.execute('delete from countries_treaties')
114
+
115
+ country = Country.new(:name => 'India')
116
+ country.country_id = 'c1'
117
+ country.save!
118
+
119
+ treaty = Treaty.new(:name => 'peace')
120
+ treaty.treaty_id = 't1'
121
+ country.treaties << treaty
122
+ end
123
+
124
+ def test_marshal_dump
125
+ post = posts :welcome
126
+ preloaded = Post.includes(:categories).find post.id
127
+ assert_equal preloaded, Marshal.load(Marshal.dump(preloaded))
128
+ end
129
+
130
+ def test_should_property_quote_string_primary_keys
131
+ setup_data_for_habtm_case
132
+
133
+ con = ActiveRecord::Base.connection
134
+ sql = 'select * from countries_treaties'
135
+ record = con.select_rows(sql).last
136
+ assert_equal 'c1', record[0]
137
+ assert_equal 't1', record[1]
138
+ end
139
+
140
+ def test_proper_usage_of_primary_keys_and_join_table
141
+ setup_data_for_habtm_case
142
+
143
+ assert_equal 'country_id', Country.primary_key
144
+ assert_equal 'treaty_id', Treaty.primary_key
145
+
146
+ country = Country.first
147
+ assert_equal 1, country.treaties.count
148
+ end
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
+
163
+ def test_has_and_belongs_to_many
164
+ david = Developer.find(1)
165
+
166
+ assert !david.projects.empty?
167
+ assert_equal 2, david.projects.size
168
+
169
+ active_record = Project.find(1)
170
+ assert !active_record.developers.empty?
171
+ assert_equal 3, active_record.developers.size
172
+ assert active_record.developers.include?(david)
173
+ end
174
+
175
+ def test_adding_single
176
+ jamis = Developer.find(2)
177
+ jamis.projects.reload # causing the collection to load
178
+ action_controller = Project.find(2)
179
+ assert_equal 1, jamis.projects.size
180
+ assert_equal 1, action_controller.developers.size
181
+
182
+ jamis.projects << action_controller
183
+
184
+ assert_equal 2, jamis.projects.size
185
+ assert_equal 2, jamis.projects.reload.size
186
+ assert_equal 2, action_controller.developers.reload.size
187
+ end
188
+
189
+ def test_adding_type_mismatch
190
+ jamis = Developer.find(2)
191
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << nil }
192
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << 1 }
193
+ end
194
+
195
+ def test_adding_from_the_project
196
+ jamis = Developer.find(2)
197
+ action_controller = Project.find(2)
198
+ action_controller.developers.reload
199
+ assert_equal 1, jamis.projects.size
200
+ assert_equal 1, action_controller.developers.size
201
+
202
+ action_controller.developers << jamis
203
+
204
+ assert_equal 2, jamis.projects.reload.size
205
+ assert_equal 2, action_controller.developers.size
206
+ assert_equal 2, action_controller.developers.reload.size
207
+ end
208
+
209
+ def test_adding_from_the_project_fixed_timestamp
210
+ jamis = Developer.find(2)
211
+ action_controller = Project.find(2)
212
+ action_controller.developers.reload
213
+ assert_equal 1, jamis.projects.size
214
+ assert_equal 1, action_controller.developers.size
215
+ updated_at = jamis.updated_at
216
+
217
+ action_controller.developers << jamis
218
+
219
+ assert_equal updated_at, jamis.updated_at
220
+ assert_equal 2, jamis.projects.reload.size
221
+ assert_equal 2, action_controller.developers.size
222
+ assert_equal 2, action_controller.developers.reload.size
223
+ end
224
+
225
+ def test_adding_multiple
226
+ aredridel = Developer.new("name" => "Aredridel")
227
+ aredridel.save
228
+ aredridel.projects.reload
229
+ aredridel.projects.push(Project.find(1), Project.find(2))
230
+ assert_equal 2, aredridel.projects.size
231
+ assert_equal 2, aredridel.projects.reload.size
232
+ end
233
+
234
+ def test_adding_a_collection
235
+ aredridel = Developer.new("name" => "Aredridel")
236
+ aredridel.save
237
+ aredridel.projects.reload
238
+ aredridel.projects.concat([Project.find(1), Project.find(2)])
239
+ assert_equal 2, aredridel.projects.size
240
+ assert_equal 2, aredridel.projects.reload.size
241
+ end
242
+
243
+ def test_habtm_adding_before_save
244
+ no_of_devels = Developer.count
245
+ no_of_projects = Project.count
246
+ aredridel = Developer.new("name" => "Aredridel")
247
+ aredridel.projects.concat([Project.find(1), p = Project.new("name" => "Projekt")])
248
+ assert !aredridel.persisted?
249
+ assert !p.persisted?
250
+ assert aredridel.save
251
+ assert aredridel.persisted?
252
+ assert_equal no_of_devels+1, Developer.count
253
+ assert_equal no_of_projects+1, Project.count
254
+ assert_equal 2, aredridel.projects.size
255
+ assert_equal 2, aredridel.projects.reload.size
256
+ end
257
+
258
+ def test_habtm_saving_multiple_relationships
259
+ new_project = Project.new("name" => "Grimetime")
260
+ amount_of_developers = 4
261
+ developers = (0...amount_of_developers).collect {|i| Developer.create(:name => "JME #{i}") }.reverse
262
+
263
+ new_project.developer_ids = [developers[0].id, developers[1].id]
264
+ new_project.developers_with_callback_ids = [developers[2].id, developers[3].id]
265
+ assert new_project.save
266
+
267
+ new_project.reload
268
+ assert_equal amount_of_developers, new_project.developers.size
269
+ assert_equal developers, new_project.developers
270
+ end
271
+
272
+ def test_habtm_distinct_order_preserved
273
+ assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).non_unique_developers
274
+ assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).developers
275
+ end
276
+
277
+ def test_habtm_collection_size_from_build
278
+ devel = Developer.create("name" => "Fred Wu")
279
+ devel.projects << Project.create("name" => "Grimetime")
280
+ devel.projects.build
281
+
282
+ assert_equal 2, devel.projects.size
283
+ end
284
+
285
+ def test_habtm_collection_size_from_params
286
+ devel = Developer.new({
287
+ projects_attributes: {
288
+ '0' => {}
289
+ }
290
+ })
291
+
292
+ assert_equal 1, devel.projects.size
293
+ end
294
+
295
+ def test_build
296
+ devel = Developer.find(1)
297
+ proj = assert_no_queries(ignore_none: false) { devel.projects.build("name" => "Projekt") }
298
+ assert !devel.projects.loaded?
299
+
300
+ assert_equal devel.projects.last, proj
301
+ assert devel.projects.loaded?
302
+
303
+ assert !proj.persisted?
304
+ devel.save
305
+ assert proj.persisted?
306
+ assert_equal devel.projects.last, proj
307
+ assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
308
+ end
309
+
310
+ def test_new_aliased_to_build
311
+ devel = Developer.find(1)
312
+ proj = assert_no_queries(ignore_none: false) { devel.projects.new("name" => "Projekt") }
313
+ assert !devel.projects.loaded?
314
+
315
+ assert_equal devel.projects.last, proj
316
+ assert devel.projects.loaded?
317
+
318
+ assert !proj.persisted?
319
+ devel.save
320
+ assert proj.persisted?
321
+ assert_equal devel.projects.last, proj
322
+ assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
323
+ end
324
+
325
+ def test_build_by_new_record
326
+ devel = Developer.new(:name => "Marcel", :salary => 75000)
327
+ devel.projects.build(:name => "Make bed")
328
+ proj2 = devel.projects.build(:name => "Lie in it")
329
+ assert_equal devel.projects.last, proj2
330
+ assert !proj2.persisted?
331
+ devel.save
332
+ assert devel.persisted?
333
+ assert proj2.persisted?
334
+ assert_equal devel.projects.last, proj2
335
+ assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
336
+ end
337
+
338
+ def test_create
339
+ devel = Developer.find(1)
340
+ proj = devel.projects.create("name" => "Projekt")
341
+ assert !devel.projects.loaded?
342
+
343
+ assert_equal devel.projects.last, proj
344
+ assert !devel.projects.loaded?
345
+
346
+ assert proj.persisted?
347
+ assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
348
+ end
349
+
350
+ def test_create_by_new_record
351
+ devel = Developer.new(:name => "Marcel", :salary => 75000)
352
+ devel.projects.build(:name => "Make bed")
353
+ proj2 = devel.projects.build(:name => "Lie in it")
354
+ assert_equal devel.projects.last, proj2
355
+ assert !proj2.persisted?
356
+ devel.save
357
+ assert devel.persisted?
358
+ assert proj2.persisted?
359
+ assert_equal devel.projects.last, proj2
360
+ assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
361
+ end
362
+
363
+ def test_creation_respects_hash_condition
364
+ # in Oracle '' is saved as null therefore need to save ' ' in not null column
365
+ post = categories(:general).post_with_conditions.build(:body => ' ')
366
+
367
+ assert post.save
368
+ assert_equal 'Yet Another Testing Title', post.title
369
+
370
+ # in Oracle '' is saved as null therefore need to save ' ' in not null column
371
+ another_post = categories(:general).post_with_conditions.create(:body => ' ')
372
+
373
+ assert another_post.persisted?
374
+ assert_equal 'Yet Another Testing Title', another_post.title
375
+ end
376
+
377
+ def test_distinct_after_the_fact
378
+ dev = developers(:jamis)
379
+ dev.projects << projects(:active_record)
380
+ dev.projects << projects(:active_record)
381
+
382
+ assert_equal 3, dev.projects.size
383
+ assert_equal 1, dev.projects.distinct.size
384
+ end
385
+
386
+ def test_distinct_before_the_fact
387
+ projects(:active_record).developers << developers(:jamis)
388
+ projects(:active_record).developers << developers(:david)
389
+ assert_equal 3, projects(:active_record, :reload).developers.size
390
+ end
391
+
392
+ def test_distinct_option_prevents_duplicate_push
393
+ project = projects(:active_record)
394
+ project.developers << developers(:jamis)
395
+ project.developers << developers(:david)
396
+ assert_equal 3, project.developers.size
397
+
398
+ project.developers << developers(:david)
399
+ project.developers << developers(:jamis)
400
+ assert_equal 3, project.developers.size
401
+ end
402
+
403
+ def test_distinct_when_association_already_loaded
404
+ project = projects(:active_record)
405
+ project.developers << [ developers(:jamis), developers(:david), developers(:jamis), developers(:david) ]
406
+ assert_equal 3, Project.includes(:developers).find(project.id).developers.size
407
+ end
408
+
409
+ def test_deleting
410
+ david = Developer.find(1)
411
+ active_record = Project.find(1)
412
+ david.projects.reload
413
+ assert_equal 2, david.projects.size
414
+ assert_equal 3, active_record.developers.size
415
+
416
+ david.projects.delete(active_record)
417
+
418
+ assert_equal 1, david.projects.size
419
+ assert_equal 1, david.projects.reload.size
420
+ assert_equal 2, active_record.developers.reload.size
421
+ end
422
+
423
+ def test_deleting_array
424
+ david = Developer.find(1)
425
+ david.projects.reload
426
+ david.projects.delete(Project.all.to_a)
427
+ assert_equal 0, david.projects.size
428
+ assert_equal 0, david.projects.reload.size
429
+ end
430
+
431
+ def test_deleting_all
432
+ david = Developer.find(1)
433
+ david.projects.reload
434
+ david.projects.clear
435
+ assert_equal 0, david.projects.size
436
+ assert_equal 0, david.projects.reload.size
437
+ end
438
+
439
+ def test_removing_associations_on_destroy
440
+ david = DeveloperWithBeforeDestroyRaise.find(1)
441
+ assert !david.projects.empty?
442
+ david.destroy
443
+ assert david.projects.empty?
444
+ assert DeveloperWithBeforeDestroyRaise.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = 1").empty?
445
+ end
446
+
447
+ def test_destroying
448
+ david = Developer.find(1)
449
+ project = Project.find(1)
450
+ david.projects.reload
451
+ assert_equal 2, david.projects.size
452
+ assert_equal 3, project.developers.size
453
+
454
+ assert_no_difference "Project.count" do
455
+ david.projects.destroy(project)
456
+ end
457
+
458
+ join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id} AND project_id = #{project.id}")
459
+ assert join_records.empty?
460
+
461
+ assert_equal 1, david.reload.projects.size
462
+ assert_equal 1, david.projects.reload.size
463
+ end
464
+
465
+ def test_destroying_many
466
+ david = Developer.find(1)
467
+ david.projects.reload
468
+ projects = Project.all.to_a
469
+
470
+ assert_no_difference "Project.count" do
471
+ david.projects.destroy(*projects)
472
+ end
473
+
474
+ join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id}")
475
+ assert join_records.empty?
476
+
477
+ assert_equal 0, david.reload.projects.size
478
+ assert_equal 0, david.projects.reload.size
479
+ end
480
+
481
+ def test_destroy_all
482
+ david = Developer.find(1)
483
+ david.projects.reload
484
+ assert !david.projects.empty?
485
+
486
+ assert_no_difference "Project.count" do
487
+ david.projects.destroy_all
488
+ end
489
+
490
+ join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id}")
491
+ assert join_records.empty?
492
+
493
+ assert david.projects.empty?
494
+ assert david.projects.reload.empty?
495
+ end
496
+
497
+ def test_destroy_associations_destroys_multiple_associations
498
+ george = parrots(:george)
499
+ assert !george.pirates.empty?
500
+ assert !george.treasures.empty?
501
+
502
+ assert_no_difference "Pirate.count" do
503
+ assert_no_difference "Treasure.count" do
504
+ george.destroy_associations
505
+ end
506
+ end
507
+
508
+ join_records = Parrot.connection.select_all("SELECT * FROM parrots_pirates WHERE parrot_id = #{george.id}")
509
+ assert join_records.empty?
510
+ assert george.pirates.reload.empty?
511
+
512
+ join_records = Parrot.connection.select_all("SELECT * FROM parrots_treasures WHERE parrot_id = #{george.id}")
513
+ assert join_records.empty?
514
+ assert george.treasures.reload.empty?
515
+ end
516
+
517
+ def test_associations_with_conditions
518
+ assert_equal 3, projects(:active_record).developers.size
519
+ assert_equal 1, projects(:active_record).developers_named_david.size
520
+ assert_equal 1, projects(:active_record).developers_named_david_with_hash_conditions.size
521
+
522
+ assert_equal developers(:david), projects(:active_record).developers_named_david.find(developers(:david).id)
523
+ assert_equal developers(:david), projects(:active_record).developers_named_david_with_hash_conditions.find(developers(:david).id)
524
+ assert_equal developers(:david), projects(:active_record).salaried_developers.find(developers(:david).id)
525
+
526
+ projects(:active_record).developers_named_david.clear
527
+ assert_equal 2, projects(:active_record, :reload).developers.size
528
+ end
529
+
530
+ def test_find_in_association
531
+ # Using sql
532
+ assert_equal developers(:david), projects(:active_record).developers.find(developers(:david).id), "SQL find"
533
+
534
+ # Using ruby
535
+ active_record = projects(:active_record)
536
+ active_record.developers.reload
537
+ assert_equal developers(:david), active_record.developers.find(developers(:david).id), "Ruby find"
538
+ end
539
+
540
+ def test_include_uses_array_include_after_loaded
541
+ project = projects(:active_record)
542
+ project.developers.load_target
543
+
544
+ developer = project.developers.first
545
+
546
+ assert_no_queries(ignore_none: false) do
547
+ assert project.developers.loaded?
548
+ assert project.developers.include?(developer)
549
+ end
550
+ end
551
+
552
+ def test_include_checks_if_record_exists_if_target_not_loaded
553
+ project = projects(:active_record)
554
+ developer = project.developers.first
555
+
556
+ project.reload
557
+ assert ! project.developers.loaded?
558
+ assert_queries(1) do
559
+ assert project.developers.include?(developer)
560
+ end
561
+ assert ! project.developers.loaded?
562
+ end
563
+
564
+ def test_include_returns_false_for_non_matching_record_to_verify_scoping
565
+ project = projects(:active_record)
566
+ developer = Developer.create :name => "Bryan", :salary => 50_000
567
+
568
+ assert ! project.developers.loaded?
569
+ assert ! project.developers.include?(developer)
570
+ end
571
+
572
+ def test_find_with_merged_options
573
+ assert_equal 1, projects(:active_record).limited_developers.size
574
+ assert_equal 1, projects(:active_record).limited_developers.to_a.size
575
+ assert_equal 3, projects(:active_record).limited_developers.limit(nil).to_a.size
576
+ end
577
+
578
+ def test_dynamic_find_should_respect_association_order
579
+ # Developers are ordered 'name DESC, id DESC'
580
+ high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
581
+
582
+ assert_equal high_id_jamis, projects(:active_record).developers.merge(:where => "name = 'Jamis'").first
583
+ assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis')
584
+ end
585
+
586
+ def test_find_should_append_to_association_order
587
+ ordered_developers = projects(:active_record).developers.order('projects.id')
588
+ assert_equal ['developers.name desc, developers.id desc', 'projects.id'], ordered_developers.order_values
589
+ end
590
+
591
+ def test_dynamic_find_all_should_respect_readonly_access
592
+ projects(:active_record).readonly_developers.each { |d| assert_raise(ActiveRecord::ReadOnlyRecord) { d.save! } if d.valid?}
593
+ projects(:active_record).readonly_developers.each(&:readonly?)
594
+ end
595
+
596
+ def test_new_with_values_in_collection
597
+ jamis = DeveloperForProjectWithAfterCreateHook.find_by_name('Jamis')
598
+ david = DeveloperForProjectWithAfterCreateHook.find_by_name('David')
599
+ project = ProjectWithAfterCreateHook.new(:name => "Cooking with Bertie")
600
+ project.developers << jamis
601
+ project.save!
602
+ project.reload
603
+
604
+ assert project.developers.include?(jamis)
605
+ assert project.developers.include?(david)
606
+ end
607
+
608
+ def test_find_in_association_with_options
609
+ developers = projects(:active_record).developers.to_a
610
+ assert_equal 3, developers.size
611
+
612
+ assert_equal developers(:poor_jamis), projects(:active_record).developers.where("salary < 10000").first
613
+ end
614
+
615
+ def test_association_with_extend_option
616
+ eponine = DeveloperWithExtendOption.create(name: 'Eponine')
617
+ assert_equal 'sns', eponine.projects.category
618
+ end
619
+
620
+ def test_replace_with_less
621
+ david = developers(:david)
622
+ david.projects = [projects(:action_controller)]
623
+ assert david.save
624
+ assert_equal 1, david.projects.length
625
+ end
626
+
627
+ def test_replace_with_new
628
+ david = developers(:david)
629
+ david.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")]
630
+ david.save
631
+ assert_equal 2, david.projects.length
632
+ assert !david.projects.include?(projects(:active_record))
633
+ end
634
+
635
+ def test_replace_on_new_object
636
+ new_developer = Developer.new("name" => "Matz")
637
+ new_developer.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")]
638
+ new_developer.save
639
+ assert_equal 2, new_developer.projects.length
640
+ end
641
+
642
+ def test_consider_type
643
+ developer = Developer.first
644
+ special_project = SpecialProject.create("name" => "Special Project")
645
+
646
+ other_project = developer.projects.first
647
+ developer.special_projects << special_project
648
+ developer.reload
649
+
650
+ assert developer.projects.include?(special_project)
651
+ assert developer.special_projects.include?(special_project)
652
+ assert !developer.special_projects.include?(other_project)
653
+ end
654
+
655
+ def test_symbol_join_table
656
+ developer = Developer.first
657
+ sp = developer.sym_special_projects.create("name" => "omg")
658
+ developer.reload
659
+ assert_includes developer.sym_special_projects, sp
660
+ end
661
+
662
+ def test_update_attributes_after_push_without_duplicate_join_table_rows
663
+ developer = Developer.new("name" => "Kano")
664
+ project = SpecialProject.create("name" => "Special Project")
665
+ assert developer.save
666
+ developer.projects << project
667
+ developer.update_columns("name" => "Bruza")
668
+ assert_equal 1, Developer.connection.select_value(<<-end_sql).to_i
669
+ SELECT count(*) FROM developers_projects
670
+ WHERE project_id = #{project.id}
671
+ AND developer_id = #{developer.id}
672
+ end_sql
673
+ end
674
+
675
+ def test_updating_attributes_on_non_rich_associations
676
+ welcome = categories(:technology).posts.first
677
+ welcome.title = "Something else"
678
+ assert welcome.save!
679
+ end
680
+
681
+ def test_habtm_respects_select
682
+ categories(:technology).select_testing_posts.reload.each do |o|
683
+ assert_respond_to o, :correctness_marker
684
+ end
685
+ assert_respond_to categories(:technology).select_testing_posts.first, :correctness_marker
686
+ end
687
+
688
+ def test_habtm_selects_all_columns_by_default
689
+ assert_equal Project.column_names.sort, developers(:david).projects.first.attributes.keys.sort
690
+ end
691
+
692
+ def test_habtm_respects_select_query_method
693
+ assert_equal ['id'], developers(:david).projects.select(:id).first.attributes.keys
694
+ end
695
+
696
+ def test_join_table_alias
697
+ # FIXME: `references` has no impact on the aliases generated for the join
698
+ # query. The fact that we pass `:developers_projects_join` to `references`
699
+ # and that the SQL string contains `developers_projects_join` is merely a
700
+ # coincidence.
701
+ assert_equal(
702
+ 3,
703
+ Developer.references(:developers_projects_join).merge(
704
+ :includes => {:projects => :developers},
705
+ :where => 'projects_developers_projects_join.joined_on IS NOT NULL'
706
+ ).to_a.size
707
+ )
708
+ end
709
+
710
+ def test_join_with_group
711
+ # FIXME: `references` has no impact on the aliases generated for the join
712
+ # query. The fact that we pass `:developers_projects_join` to `references`
713
+ # and that the SQL string contains `developers_projects_join` is merely a
714
+ # coincidence.
715
+ group = Developer.columns.inject([]) do |g, c|
716
+ g << "developers.#{c.name}"
717
+ g << "developers_projects_2.#{c.name}"
718
+ end
719
+ Project.columns.each { |c| group << "projects.#{c.name}" }
720
+
721
+ assert_equal(
722
+ 3,
723
+ Developer.references(:developers_projects_join).merge(
724
+ :includes => {:projects => :developers}, :where => 'projects_developers_projects_join.joined_on IS NOT NULL',
725
+ :group => group.join(",")
726
+ ).to_a.size
727
+ )
728
+ end
729
+
730
+ def test_find_grouped
731
+ all_posts_from_category1 = Post.all.merge!(:where => "category_id = 1", :joins => :categories).to_a
732
+ grouped_posts_of_category1 = Post.all.merge!(:where => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories).to_a
733
+ assert_equal 5, all_posts_from_category1.size
734
+ assert_equal 2, grouped_posts_of_category1.size
735
+ end
736
+
737
+ def test_find_scoped_grouped
738
+ assert_equal 5, categories(:general).posts_grouped_by_title.to_a.size
739
+ assert_equal 1, categories(:technology).posts_grouped_by_title.to_a.size
740
+ end
741
+
742
+ def test_find_scoped_grouped_having
743
+ assert_equal 2, projects(:active_record).well_payed_salary_groups.to_a.size
744
+ assert projects(:active_record).well_payed_salary_groups.all? { |g| g.salary > 10000 }
745
+ end
746
+
747
+ def test_get_ids
748
+ assert_equal projects(:active_record, :action_controller).map(&:id).sort, developers(:david).project_ids.sort
749
+ assert_equal [projects(:active_record).id], developers(:jamis).project_ids
750
+ end
751
+
752
+ def test_get_ids_for_loaded_associations
753
+ developer = developers(:david)
754
+ developer.projects.reload
755
+ assert_queries(0) do
756
+ developer.project_ids
757
+ developer.project_ids
758
+ end
759
+ end
760
+
761
+ def test_get_ids_for_unloaded_associations_does_not_load_them
762
+ developer = developers(:david)
763
+ assert !developer.projects.loaded?
764
+ assert_equal projects(:active_record, :action_controller).map(&:id).sort, developer.project_ids.sort
765
+ assert !developer.projects.loaded?
766
+ end
767
+
768
+ def test_assign_ids
769
+ developer = Developer.new("name" => "Joe")
770
+ developer.project_ids = projects(:active_record, :action_controller).map(&:id)
771
+ developer.save
772
+ developer.reload
773
+ assert_equal 2, developer.projects.length
774
+ assert_equal [projects(:active_record), projects(:action_controller)].map(&:id).sort, developer.project_ids.sort
775
+ end
776
+
777
+ def test_assign_ids_ignoring_blanks
778
+ developer = Developer.new("name" => "Joe")
779
+ developer.project_ids = [projects(:active_record).id, nil, projects(:action_controller).id, '']
780
+ developer.save
781
+ developer.reload
782
+ assert_equal 2, developer.projects.length
783
+ assert_equal [projects(:active_record), projects(:action_controller)].map(&:id).sort, developer.project_ids.sort
784
+ end
785
+
786
+ def test_scoped_find_on_through_association_doesnt_return_read_only_records
787
+ tag = Post.find(1).tags.find_by_name("General")
788
+
789
+ assert_nothing_raised do
790
+ tag.save!
791
+ end
792
+ end
793
+
794
+ def test_has_many_through_polymorphic_has_manys_works
795
+ assert_equal [10, 20].to_set, pirates(:redbeard).treasure_estimates.map(&:price).to_set
796
+ end
797
+
798
+ def test_symbols_as_keys
799
+ developer = DeveloperWithSymbolsForKeys.new(:name => 'David')
800
+ project = ProjectWithSymbolsForKeys.new(:name => 'Rails Testing')
801
+ project.developers << developer
802
+ project.save!
803
+
804
+ assert_equal 1, project.developers.size
805
+ assert_equal 1, developer.projects.size
806
+ assert_equal developer, project.developers.first
807
+ assert_equal project, developer.projects.first
808
+ end
809
+
810
+ def test_dynamic_find_should_respect_association_include
811
+ # SQL error in sort clause if :include is not included
812
+ # due to Unknown column 'authors.id'
813
+ assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog')
814
+ end
815
+
816
+ def test_count
817
+ david = Developer.find(1)
818
+ assert_equal 2, david.projects.count
819
+ end
820
+
821
+ def test_association_proxy_transaction_method_starts_transaction_in_association_class
822
+ assert_called(Post, :transaction) do
823
+ Category.first.posts.transaction do
824
+ # nothing
825
+ end
826
+ end
827
+ end
828
+
829
+ def test_caching_of_columns
830
+ david = Developer.find(1)
831
+ # clear cache possibly created by other tests
832
+ david.projects.reset_column_information
833
+
834
+ assert_queries(:any) { david.projects.columns }
835
+ assert_no_queries { david.projects.columns }
836
+
837
+ ## and again to verify that reset_column_information clears the cache correctly
838
+ david.projects.reset_column_information
839
+
840
+ assert_queries(:any) { david.projects.columns }
841
+ assert_no_queries { david.projects.columns }
842
+ end
843
+
844
+ def test_attributes_are_being_set_when_initialized_from_habtm_association_with_where_clause
845
+ new_developer = projects(:action_controller).developers.where(:name => "Marcelo").build
846
+ assert_equal new_developer.name, "Marcelo"
847
+ end
848
+
849
+ def test_attributes_are_being_set_when_initialized_from_habtm_association_with_multiple_where_clauses
850
+ new_developer = projects(:action_controller).developers.where(:name => "Marcelo").where(:salary => 90_000).build
851
+ assert_equal new_developer.name, "Marcelo"
852
+ assert_equal new_developer.salary, 90_000
853
+ end
854
+
855
+ def test_include_method_in_has_and_belongs_to_many_association_should_return_true_for_instance_added_with_build
856
+ project = Project.new
857
+ developer = project.developers.build
858
+ assert project.developers.include?(developer)
859
+ end
860
+
861
+ def test_destruction_does_not_error_without_primary_key
862
+ redbeard = pirates(:redbeard)
863
+ george = parrots(:george)
864
+ redbeard.parrots << george
865
+ assert_equal 2, george.pirates.count
866
+ Pirate.includes(:parrots).where(parrot: redbeard.parrot).find(redbeard.id).destroy
867
+ assert_equal 1, george.pirates.count
868
+ assert_equal [], Pirate.where(id: redbeard.id)
869
+ end
870
+
871
+ def test_has_and_belongs_to_many_associations_on_new_records_use_null_relations
872
+ projects = Developer.new.projects
873
+ assert_no_queries(ignore_none: false) do
874
+ assert_equal [], projects
875
+ assert_equal [], projects.where(title: 'omg')
876
+ assert_equal [], projects.pluck(:title)
877
+ assert_equal 0, projects.count
878
+ end
879
+ end
880
+
881
+ def test_association_with_validate_false_does_not_run_associated_validation_callbacks_on_create
882
+ rich_person = RichPerson.new
883
+
884
+ treasure = Treasure.new
885
+ treasure.rich_people << rich_person
886
+ treasure.valid?
887
+
888
+ assert_equal 1, treasure.rich_people.size
889
+ assert_nil rich_person.first_name, 'should not run associated person validation on create when validate: false'
890
+ end
891
+
892
+ def test_association_with_validate_false_does_not_run_associated_validation_callbacks_on_update
893
+ rich_person = RichPerson.create!
894
+ person_first_name = rich_person.first_name
895
+ assert_not_nil person_first_name
896
+
897
+ treasure = Treasure.new
898
+ treasure.rich_people << rich_person
899
+ treasure.valid?
900
+
901
+ assert_equal 1, treasure.rich_people.size
902
+ assert_equal person_first_name, rich_person.first_name, 'should not run associated person validation on update when validate: false'
903
+ end
904
+
905
+ def test_custom_join_table
906
+ assert_equal 'edges', Vertex.reflect_on_association(:sources).join_table
907
+ end
908
+
909
+ def test_has_and_belongs_to_many_in_a_namespaced_model_pointing_to_a_namespaced_model
910
+ magazine = Publisher::Magazine.create
911
+ article = Publisher::Article.create
912
+ magazine.articles << article
913
+ magazine.save
914
+
915
+ assert_includes magazine.articles, article
916
+ end
917
+
918
+ def test_has_and_belongs_to_many_in_a_namespaced_model_pointing_to_a_non_namespaced_model
919
+ article = Publisher::Article.create
920
+ tag = Tag.create
921
+ article.tags << tag
922
+ article.save
923
+
924
+ assert_includes article.tags, tag
925
+ end
926
+
927
+ def test_redefine_habtm
928
+ child = SubDeveloper.new("name" => "Aredridel")
929
+ child.special_projects << SpecialProject.new("name" => "Special Project")
930
+ assert child.save, 'child object should be saved'
931
+ end
932
+
933
+ def test_habtm_with_reflection_using_class_name_and_fixtures
934
+ assert_not_nil Developer._reflections['shared_computers']
935
+ # Checking the fixture for named association is important here, because it's the only way
936
+ # we've been able to reproduce this bug
937
+ assert_not_nil File.read(File.expand_path("../../../fixtures/developers.yml", __FILE__)).index("shared_computers")
938
+ assert_equal developers(:david).shared_computers.first, computers(:laptop)
939
+ end
940
+
941
+ def test_with_symbol_class_name
942
+ assert_nothing_raised do
943
+ DeveloperWithSymbolClassName.new
944
+ end
945
+ end
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
+
953
+ def test_alternate_database
954
+ professor = Professor.create(name: "Plum")
955
+ course = Course.create(name: "Forensics")
956
+ assert_equal 0, professor.courses.count
957
+ assert_nothing_raised do
958
+ professor.courses << course
959
+ end
960
+ assert_equal 1, professor.courses.count
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
1004
+ end