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

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