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,21 +1,16 @@
1
- require 'cases/helper'
2
- require 'models/post'
3
- require 'models/author'
4
-
5
- module ActiveRecord
6
- module Associations
7
- class AssociationScopeTest < ActiveRecord::TestCase
8
- test 'does not duplicate conditions' do
9
- scope = AssociationScope.scope(Author.new.association(:welcome_posts),
10
- Author.connection)
11
- wheres = scope.where_values.map(&:right)
12
- binds = scope.bind_values.map(&:last)
13
- wheres = scope.where_values.map(&:right).reject { |node|
14
- Arel::Nodes::BindParam === node
15
- }
16
- assert_equal wheres.uniq, wheres
17
- assert_equal binds.uniq, binds
18
- end
19
- end
20
- end
21
- end
1
+ require 'cases/helper'
2
+ require 'models/post'
3
+ require 'models/author'
4
+
5
+ module ActiveRecord
6
+ module Associations
7
+ class AssociationScopeTest < ActiveRecord::TestCase
8
+ test 'does not duplicate conditions' do
9
+ scope = AssociationScope.scope(Author.new.association(:welcome_posts),
10
+ Author.connection)
11
+ binds = scope.where_clause.binds.map(&:value)
12
+ assert_equal binds.uniq, binds
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,1029 +1,1141 @@
1
- require 'cases/helper'
2
- require 'models/developer'
3
- require 'models/computer'
4
- require 'models/project'
5
- require 'models/company'
6
- require 'models/topic'
7
- require 'models/reply'
8
- require 'models/computer'
9
- require 'models/post'
10
- require 'models/author'
11
- require 'models/tag'
12
- require 'models/tagging'
13
- require 'models/comment'
14
- require 'models/sponsor'
15
- require 'models/member'
16
- require 'models/essay'
17
- require 'models/toy'
18
- require 'models/invoice'
19
- require 'models/line_item'
20
- require 'models/column'
21
- require 'models/record'
22
- require 'models/admin'
23
- require 'models/admin/user'
24
- require 'models/ship'
25
- require 'models/treasure'
26
- require 'models/parrot'
27
-
28
- class BelongsToAssociationsTest < ActiveRecord::TestCase
29
- fixtures :accounts, :companies, :developers, :projects, :topics,
30
- :developers_projects, :computers, :authors, :author_addresses,
31
- :posts, :tags, :taggings, :comments, :sponsors, :members
32
-
33
- def test_belongs_to
34
- firm = Client.find(3).firm
35
- assert_not_nil firm
36
- assert_equal companies(:first_firm).name, firm.name
37
- end
38
-
39
- def test_belongs_to_does_not_use_order_by
40
- ActiveRecord::SQLCounter.clear_log
41
- Client.find(3).firm
42
- ensure
43
- assert ActiveRecord::SQLCounter.log_all.all? { |sql| /order by/i !~ sql }, 'ORDER BY was used in the query'
44
- end
45
-
46
- def test_belongs_to_with_primary_key
47
- client = Client.create(:name => "Primary key client", :firm_name => companies(:first_firm).name)
48
- assert_equal companies(:first_firm).name, client.firm_with_primary_key.name
49
- end
50
-
51
- def test_belongs_to_with_primary_key_joins_on_correct_column
52
- sql = Client.joins(:firm_with_primary_key).to_sql
53
- if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
54
- assert_no_match(/`firm_with_primary_keys_companies`\.`id`/, sql)
55
- assert_match(/`firm_with_primary_keys_companies`\.`name`/, sql)
56
- elsif current_adapter?(:OracleAdapter)
57
- # on Oracle aliases are truncated to 30 characters and are quoted in uppercase
58
- assert_no_match(/"firm_with_primary_keys_compani"\."id"/i, sql)
59
- assert_match(/"firm_with_primary_keys_compani"\."name"/i, sql)
60
- elsif current_adapter?(:IBM_DBAdapter)
61
- # Quoting of column names is not necessary for IBM_DB
62
- assert_no_match(/firm_with_primary_keys_companies\.id/i, sql)
63
- assert_match(/firm_with_primary_keys_companies\.name/i, sql)
64
- else
65
- assert_no_match(/"firm_with_primary_keys_companies"\."id"/, sql)
66
- assert_match(/"firm_with_primary_keys_companies"\."name"/, sql)
67
- end
68
- end
69
-
70
- def test_default_scope_on_relations_is_not_cached
71
- counter = 0
72
-
73
- comments = Class.new(ActiveRecord::Base) {
74
- self.table_name = 'comments'
75
- self.inheritance_column = 'not_there'
76
-
77
- posts = Class.new(ActiveRecord::Base) {
78
- self.table_name = 'posts'
79
- self.inheritance_column = 'not_there'
80
-
81
- default_scope -> {
82
- counter += 1
83
- where("id = :inc", :inc => counter)
84
- }
85
-
86
- has_many :comments, :anonymous_class => comments
87
- }
88
- belongs_to :post, :anonymous_class => posts, :inverse_of => false
89
- }
90
-
91
- assert_equal 0, counter
92
- comment = comments.first
93
- assert_equal 0, counter
94
- sql = capture_sql { comment.post }
95
- comment.reload
96
- assert_not_equal sql, capture_sql { comment.post }
97
- end
98
-
99
- def test_proxy_assignment
100
- account = Account.find(1)
101
- assert_nothing_raised { account.firm = account.firm }
102
- end
103
-
104
- def test_type_mismatch
105
- assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = 1 }
106
- assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) }
107
- end
108
-
109
- def test_raises_type_mismatch_with_namespaced_class
110
- assert_nil defined?(Region), "This test requires that there is no top-level Region class"
111
-
112
- ActiveRecord::Base.connection.instance_eval do
113
- create_table(:admin_regions) { |t| t.string :name }
114
- add_column :admin_users, :region_id, :integer
115
- end
116
- Admin.const_set "RegionalUser", Class.new(Admin::User) { belongs_to(:region) }
117
- Admin.const_set "Region", Class.new(ActiveRecord::Base)
118
-
119
- e = assert_raise(ActiveRecord::AssociationTypeMismatch) {
120
- Admin::RegionalUser.new(region: 'wrong value')
121
- }
122
- assert_match(/^Region\([^)]+\) expected, got String\([^)]+\)$/, e.message)
123
- ensure
124
- Admin.send :remove_const, "Region" if Admin.const_defined?("Region")
125
- Admin.send :remove_const, "RegionalUser" if Admin.const_defined?("RegionalUser")
126
-
127
- ActiveRecord::Base.connection.instance_eval do
128
- remove_column :admin_users, :region_id if column_exists?(:admin_users, :region_id)
129
- drop_table :admin_regions, if_exists: true
130
- end
131
- end
132
-
133
- def test_natural_assignment
134
- apple = Firm.create("name" => "Apple")
135
- citibank = Account.create("credit_limit" => 10)
136
- citibank.firm = apple
137
- assert_equal apple.id, citibank.firm_id
138
- end
139
-
140
- def test_id_assignment
141
- apple = Firm.create("name" => "Apple")
142
- citibank = Account.create("credit_limit" => 10)
143
- citibank.firm_id = apple
144
- assert_nil citibank.firm_id
145
- end
146
-
147
- def test_natural_assignment_with_primary_key
148
- apple = Firm.create("name" => "Apple")
149
- citibank = Client.create("name" => "Primary key client")
150
- citibank.firm_with_primary_key = apple
151
- assert_equal apple.name, citibank.firm_name
152
- end
153
-
154
- def test_eager_loading_with_primary_key
155
- Firm.create("name" => "Apple")
156
- Client.create("name" => "Citibank", :firm_name => "Apple")
157
- citibank_result = Client.all.merge!(:where => {:name => "Citibank"}, :includes => :firm_with_primary_key).first
158
- assert citibank_result.association(:firm_with_primary_key).loaded?
159
- end
160
-
161
- def test_eager_loading_with_primary_key_as_symbol
162
- Firm.create("name" => "Apple")
163
- Client.create("name" => "Citibank", :firm_name => "Apple")
164
- citibank_result = Client.all.merge!(:where => {:name => "Citibank"}, :includes => :firm_with_primary_key_symbols).first
165
- assert citibank_result.association(:firm_with_primary_key_symbols).loaded?
166
- end
167
-
168
- def test_creating_the_belonging_object
169
- citibank = Account.create("credit_limit" => 10)
170
- apple = citibank.create_firm("name" => "Apple")
171
- assert_equal apple, citibank.firm
172
- citibank.save
173
- citibank.reload
174
- assert_equal apple, citibank.firm
175
- end
176
-
177
- def test_creating_the_belonging_object_with_primary_key
178
- client = Client.create(:name => "Primary key client")
179
- apple = client.create_firm_with_primary_key("name" => "Apple")
180
- assert_equal apple, client.firm_with_primary_key
181
- client.save
182
- client.reload
183
- assert_equal apple, client.firm_with_primary_key
184
- end
185
-
186
- def test_building_the_belonging_object
187
- citibank = Account.create("credit_limit" => 10)
188
- apple = citibank.build_firm("name" => "Apple")
189
- citibank.save
190
- assert_equal apple.id, citibank.firm_id
191
- end
192
-
193
- def test_building_the_belonging_object_with_implicit_sti_base_class
194
- account = Account.new
195
- company = account.build_firm
196
- assert_kind_of Company, company, "Expected #{company.class} to be a Company"
197
- end
198
-
199
- def test_building_the_belonging_object_with_explicit_sti_base_class
200
- account = Account.new
201
- company = account.build_firm(:type => "Company")
202
- assert_kind_of Company, company, "Expected #{company.class} to be a Company"
203
- end
204
-
205
- def test_building_the_belonging_object_with_sti_subclass
206
- account = Account.new
207
- company = account.build_firm(:type => "Firm")
208
- assert_kind_of Firm, company, "Expected #{company.class} to be a Firm"
209
- end
210
-
211
- def test_building_the_belonging_object_with_an_invalid_type
212
- account = Account.new
213
- assert_raise(ActiveRecord::SubclassNotFound) { account.build_firm(:type => "InvalidType") }
214
- end
215
-
216
- def test_building_the_belonging_object_with_an_unrelated_type
217
- account = Account.new
218
- assert_raise(ActiveRecord::SubclassNotFound) { account.build_firm(:type => "Account") }
219
- end
220
-
221
- def test_building_the_belonging_object_with_primary_key
222
- client = Client.create(:name => "Primary key client")
223
- apple = client.build_firm_with_primary_key("name" => "Apple")
224
- client.save
225
- assert_equal apple.name, client.firm_name
226
- end
227
-
228
- def test_create!
229
- client = Client.create!(:name => "Jimmy")
230
- account = client.create_account!(:credit_limit => 10)
231
- assert_equal account, client.account
232
- assert account.persisted?
233
- client.save
234
- client.reload
235
- assert_equal account, client.account
236
- end
237
-
238
- def test_failing_create!
239
- client = Client.create!(:name => "Jimmy")
240
- assert_raise(ActiveRecord::RecordInvalid) { client.create_account! }
241
- assert_not_nil client.account
242
- assert client.account.new_record?
243
- end
244
-
245
- def test_natural_assignment_to_nil
246
- client = Client.find(3)
247
- client.firm = nil
248
- client.save
249
- assert_nil client.firm(true)
250
- assert_nil client.client_of
251
- end
252
-
253
- def test_natural_assignment_to_nil_with_primary_key
254
- client = Client.create(:name => "Primary key client", :firm_name => companies(:first_firm).name)
255
- client.firm_with_primary_key = nil
256
- client.save
257
- assert_nil client.firm_with_primary_key(true)
258
- assert_nil client.client_of
259
- end
260
-
261
- def test_with_different_class_name
262
- assert_equal Company.find(1).name, Company.find(3).firm_with_other_name.name
263
- assert_not_nil Company.find(3).firm_with_other_name, "Microsoft should have a firm"
264
- end
265
-
266
- def test_with_condition
267
- assert_equal Company.find(1).name, Company.find(3).firm_with_condition.name
268
- assert_not_nil Company.find(3).firm_with_condition, "Microsoft should have a firm"
269
- end
270
-
271
- def test_polymorphic_association_class
272
- sponsor = Sponsor.new
273
- assert_nil sponsor.association(:sponsorable).send(:klass)
274
- assert_nil sponsor.sponsorable(force_reload: true)
275
-
276
- sponsor.sponsorable_type = '' # the column doesn't have to be declared NOT NULL
277
- assert_nil sponsor.association(:sponsorable).send(:klass)
278
- assert_nil sponsor.sponsorable(force_reload: true)
279
-
280
- sponsor.sponsorable = Member.new :name => "Bert"
281
- assert_equal Member, sponsor.association(:sponsorable).send(:klass)
282
- assert_equal "members", sponsor.association(:sponsorable).aliased_table_name
283
- end
284
-
285
- def test_with_polymorphic_and_condition
286
- sponsor = Sponsor.create
287
- member = Member.create :name => "Bert"
288
- sponsor.sponsorable = member
289
-
290
- assert_equal member, sponsor.sponsorable
291
- assert_nil sponsor.sponsorable_with_conditions
292
- end
293
-
294
- def test_with_select
295
- assert_equal 1, Company.find(2).firm_with_select.attributes.size
296
- assert_equal 1, Company.all.merge!(:includes => :firm_with_select ).find(2).firm_with_select.attributes.size
297
- end
298
-
299
- def test_belongs_to_without_counter_cache_option
300
- # Ship has a conventionally named `treasures_count` column, but the counter_cache
301
- # option is not given on the association.
302
- ship = Ship.create(name: 'Countless')
303
-
304
- assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed unless counter_cache is given on the relation" do
305
- treasure = Treasure.new(name: 'Gold', ship: ship)
306
- treasure.save
307
- end
308
-
309
- assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed unless counter_cache is given on the relation" do
310
- treasure = ship.treasures.first
311
- treasure.destroy
312
- end
313
- end
314
-
315
- def test_belongs_to_counter
316
- debate = Topic.create("title" => "debate")
317
- assert_equal 0, debate.read_attribute("replies_count"), "No replies yet"
318
-
319
- trash = debate.replies.create("title" => "blah!", "content" => "world around!")
320
- assert_equal 1, Topic.find(debate.id).read_attribute("replies_count"), "First reply created"
321
-
322
- trash.destroy
323
- assert_equal 0, Topic.find(debate.id).read_attribute("replies_count"), "First reply deleted"
324
- end
325
-
326
- def test_belongs_to_counter_with_assigning_nil
327
- post = Post.find(1)
328
- comment = Comment.find(1)
329
-
330
- assert_equal post.id, comment.post_id
331
- assert_equal 2, Post.find(post.id).comments.size
332
-
333
- comment.post = nil
334
-
335
- assert_equal 1, Post.find(post.id).comments.size
336
- end
337
-
338
- def test_belongs_to_with_primary_key_counter
339
- debate = Topic.create("title" => "debate")
340
- debate2 = Topic.create("title" => "debate2")
341
- reply = Reply.create("title" => "blah!", "content" => "world around!", "parent_title" => "debate")
342
-
343
- assert_equal 1, debate.reload.replies_count
344
- assert_equal 0, debate2.reload.replies_count
345
-
346
- reply.topic_with_primary_key = debate2
347
-
348
- assert_equal 0, debate.reload.replies_count
349
- assert_equal 1, debate2.reload.replies_count
350
-
351
- reply.topic_with_primary_key = nil
352
-
353
- assert_equal 0, debate.reload.replies_count
354
- assert_equal 0, debate2.reload.replies_count
355
- end
356
-
357
- def test_belongs_to_counter_with_reassigning
358
- topic1 = Topic.create("title" => "t1")
359
- topic2 = Topic.create("title" => "t2")
360
- reply1 = Reply.new("title" => "r1", "content" => "r1")
361
- reply1.topic = topic1
362
-
363
- assert reply1.save
364
- assert_equal 1, Topic.find(topic1.id).replies.size
365
- assert_equal 0, Topic.find(topic2.id).replies.size
366
-
367
- reply1.topic = Topic.find(topic2.id)
368
-
369
- assert_no_queries do
370
- reply1.topic = topic2
371
- end
372
-
373
- assert reply1.save
374
- assert_equal 0, Topic.find(topic1.id).replies.size
375
- assert_equal 1, Topic.find(topic2.id).replies.size
376
-
377
- reply1.topic = nil
378
-
379
- assert_equal 0, Topic.find(topic1.id).replies.size
380
- assert_equal 0, Topic.find(topic2.id).replies.size
381
-
382
- reply1.topic = topic1
383
-
384
- assert_equal 1, Topic.find(topic1.id).replies.size
385
- assert_equal 0, Topic.find(topic2.id).replies.size
386
-
387
- reply1.destroy
388
-
389
- assert_equal 0, Topic.find(topic1.id).replies.size
390
- assert_equal 0, Topic.find(topic2.id).replies.size
391
- end
392
-
393
- def test_belongs_to_reassign_with_namespaced_models_and_counters
394
- topic1 = Web::Topic.create("title" => "t1")
395
- topic2 = Web::Topic.create("title" => "t2")
396
- reply1 = Web::Reply.new("title" => "r1", "content" => "r1")
397
- reply1.topic = topic1
398
-
399
- assert reply1.save
400
- assert_equal 1, Web::Topic.find(topic1.id).replies.size
401
- assert_equal 0, Web::Topic.find(topic2.id).replies.size
402
-
403
- reply1.topic = Web::Topic.find(topic2.id)
404
-
405
- assert reply1.save
406
- assert_equal 0, Web::Topic.find(topic1.id).replies.size
407
- assert_equal 1, Web::Topic.find(topic2.id).replies.size
408
- end
409
-
410
- def test_belongs_to_counter_after_save
411
- topic = Topic.create!(:title => "monday night")
412
- topic.replies.create!(:title => "re: monday night", :content => "football")
413
- assert_equal 1, Topic.find(topic.id)[:replies_count]
414
-
415
- topic.save!
416
- assert_equal 1, Topic.find(topic.id)[:replies_count]
417
- end
418
-
419
- def test_belongs_to_with_touch_option_on_touch
420
- line_item = LineItem.create!
421
- Invoice.create!(line_items: [line_item])
422
-
423
- assert_queries(1) { line_item.touch }
424
- end
425
-
426
- def test_belongs_to_with_touch_option_on_touch_without_updated_at_attributes
427
- assert_not LineItem.column_names.include?("updated_at")
428
-
429
- line_item = LineItem.create!
430
- invoice = Invoice.create!(line_items: [line_item])
431
- initial = invoice.updated_at
432
- line_item.touch
433
-
434
- assert_not_equal initial, invoice.reload.updated_at
435
- end
436
-
437
- def test_belongs_to_with_touch_option_on_touch_and_removed_parent
438
- line_item = LineItem.create!
439
- Invoice.create!(line_items: [line_item])
440
-
441
- line_item.invoice = nil
442
-
443
- assert_queries(2) { line_item.touch }
444
- end
445
-
446
- def test_belongs_to_with_touch_option_on_update
447
- line_item = LineItem.create!
448
- Invoice.create!(line_items: [line_item])
449
-
450
- assert_queries(2) { line_item.update amount: 10 }
451
- end
452
-
453
- def test_belongs_to_with_touch_option_on_empty_update
454
- line_item = LineItem.create!
455
- Invoice.create!(line_items: [line_item])
456
-
457
- assert_queries(0) { line_item.save }
458
- end
459
-
460
- def test_belongs_to_with_touch_option_on_destroy
461
- line_item = LineItem.create!
462
- Invoice.create!(line_items: [line_item])
463
-
464
- assert_queries(2) { line_item.destroy }
465
- end
466
-
467
- def test_belongs_to_with_touch_option_on_destroy_with_destroyed_parent
468
- line_item = LineItem.create!
469
- invoice = Invoice.create!(line_items: [line_item])
470
- invoice.destroy
471
-
472
- assert_queries(1) { line_item.destroy }
473
- end
474
-
475
- def test_belongs_to_with_touch_option_on_touch_and_reassigned_parent
476
- line_item = LineItem.create!
477
- Invoice.create!(line_items: [line_item])
478
-
479
- line_item.invoice = Invoice.create!
480
-
481
- assert_queries(3) { line_item.touch }
482
- end
483
-
484
- def test_belongs_to_counter_after_update
485
- topic = Topic.create!(title: "37s")
486
- topic.replies.create!(title: "re: 37s", content: "rails")
487
- assert_equal 1, Topic.find(topic.id)[:replies_count]
488
-
489
- topic.update(title: "37signals")
490
- assert_equal 1, Topic.find(topic.id)[:replies_count]
491
- end
492
-
493
- def test_belongs_to_counter_when_update_columns
494
- topic = Topic.create!(:title => "37s")
495
- topic.replies.create!(:title => "re: 37s", :content => "rails")
496
- assert_equal 1, Topic.find(topic.id)[:replies_count]
497
-
498
- topic.update_columns(content: "rails is wonderful")
499
- assert_equal 1, Topic.find(topic.id)[:replies_count]
500
- end
501
-
502
- def test_assignment_before_child_saved
503
- final_cut = Client.new("name" => "Final Cut")
504
- firm = Firm.find(1)
505
- final_cut.firm = firm
506
- assert !final_cut.persisted?
507
- assert final_cut.save
508
- assert final_cut.persisted?
509
- assert firm.persisted?
510
- assert_equal firm, final_cut.firm
511
- assert_equal firm, final_cut.firm(true)
512
- end
513
-
514
- def test_assignment_before_child_saved_with_primary_key
515
- final_cut = Client.new("name" => "Final Cut")
516
- firm = Firm.find(1)
517
- final_cut.firm_with_primary_key = firm
518
- assert !final_cut.persisted?
519
- assert final_cut.save
520
- assert final_cut.persisted?
521
- assert firm.persisted?
522
- assert_equal firm, final_cut.firm_with_primary_key
523
- assert_equal firm, final_cut.firm_with_primary_key(true)
524
- end
525
-
526
- def test_new_record_with_foreign_key_but_no_object
527
- client = Client.new("firm_id" => 1)
528
- # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
529
- assert_equal Firm.all.merge!(:order => "id").first, client.firm_with_basic_id
530
- end
531
-
532
- def test_setting_foreign_key_after_nil_target_loaded
533
- client = Client.new
534
- client.firm_with_basic_id
535
- client.firm_id = 1
536
-
537
- assert_equal companies(:first_firm), client.firm_with_basic_id
538
- end
539
-
540
- def test_polymorphic_setting_foreign_key_after_nil_target_loaded
541
- sponsor = Sponsor.new
542
- sponsor.sponsorable
543
- sponsor.sponsorable_id = 1
544
- sponsor.sponsorable_type = "Member"
545
-
546
- assert_equal members(:groucho), sponsor.sponsorable
547
- end
548
-
549
- def test_dont_find_target_when_foreign_key_is_null
550
- tagging = taggings(:thinking_general)
551
- assert_queries(0) { tagging.super_tag }
552
- end
553
-
554
- def test_field_name_same_as_foreign_key
555
- computer = Computer.find(1)
556
- assert_not_nil computer.developer, ":foreign key == attribute didn't lock up" # '
557
- end
558
-
559
- def test_counter_cache
560
- topic = Topic.create :title => "Zoom-zoom-zoom"
561
- assert_equal 0, topic[:replies_count]
562
-
563
- reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
564
- reply.topic = topic
565
-
566
- assert_equal 1, topic.reload[:replies_count]
567
- assert_equal 1, topic.replies.size
568
-
569
- topic[:replies_count] = 15
570
- assert_equal 15, topic.replies.size
571
- end
572
-
573
- def test_counter_cache_double_destroy
574
- topic = Topic.create :title => "Zoom-zoom-zoom"
575
-
576
- 5.times do
577
- topic.replies.create(:title => "re: zoom", :content => "speedy quick!")
578
- end
579
-
580
- assert_equal 5, topic.reload[:replies_count]
581
- assert_equal 5, topic.replies.size
582
-
583
- reply = topic.replies.first
584
-
585
- reply.destroy
586
- assert_equal 4, topic.reload[:replies_count]
587
-
588
- reply.destroy
589
- assert_equal 4, topic.reload[:replies_count]
590
- assert_equal 4, topic.replies.size
591
- end
592
-
593
- def test_concurrent_counter_cache_double_destroy
594
- topic = Topic.create :title => "Zoom-zoom-zoom"
595
-
596
- 5.times do
597
- topic.replies.create(:title => "re: zoom", :content => "speedy quick!")
598
- end
599
-
600
- assert_equal 5, topic.reload[:replies_count]
601
- assert_equal 5, topic.replies.size
602
-
603
- reply = topic.replies.first
604
- reply_clone = Reply.find(reply.id)
605
-
606
- reply.destroy
607
- assert_equal 4, topic.reload[:replies_count]
608
-
609
- reply_clone.destroy
610
- assert_equal 4, topic.reload[:replies_count]
611
- assert_equal 4, topic.replies.size
612
- end
613
-
614
- def test_custom_counter_cache
615
- reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
616
- assert_equal 0, reply[:replies_count]
617
-
618
- silly = SillyReply.create(:title => "gaga", :content => "boo-boo")
619
- silly.reply = reply
620
-
621
- assert_equal 1, reply.reload[:replies_count]
622
- assert_equal 1, reply.replies.size
623
-
624
- reply[:replies_count] = 17
625
- assert_equal 17, reply.replies.size
626
- end
627
-
628
- def test_association_assignment_sticks
629
- post = Post.first
630
-
631
- author1, author2 = Author.all.merge!(:limit => 2).to_a
632
- assert_not_nil author1
633
- assert_not_nil author2
634
-
635
- # make sure the association is loaded
636
- post.author
637
-
638
- # set the association by id, directly
639
- post.author_id = author2.id
640
-
641
- # save and reload
642
- post.save!
643
- post.reload
644
-
645
- # the author id of the post should be the id we set
646
- assert_equal post.author_id, author2.id
647
- end
648
-
649
- def test_cant_save_readonly_association
650
- assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_client).readonly_firm.save! }
651
- assert companies(:first_client).readonly_firm.readonly?
652
- end
653
-
654
- def test_test_polymorphic_assignment_foreign_key_type_string
655
- comment = Comment.first
656
- comment.author = Author.first
657
- comment.resource = Member.first
658
- comment.save
659
-
660
- assert_equal Comment.all.to_a,
661
- Comment.includes(:author).to_a
662
-
663
- assert_equal Comment.all.to_a,
664
- Comment.includes(:resource).to_a
665
- end
666
-
667
- def test_polymorphic_assignment_foreign_type_field_updating
668
- # should update when assigning a saved record
669
- sponsor = Sponsor.new
670
- member = Member.create
671
- sponsor.sponsorable = member
672
- assert_equal "Member", sponsor.sponsorable_type
673
-
674
- # should update when assigning a new record
675
- sponsor = Sponsor.new
676
- member = Member.new
677
- sponsor.sponsorable = member
678
- assert_equal "Member", sponsor.sponsorable_type
679
- end
680
-
681
- def test_polymorphic_assignment_with_primary_key_foreign_type_field_updating
682
- # should update when assigning a saved record
683
- essay = Essay.new
684
- writer = Author.create(:name => "David")
685
- essay.writer = writer
686
- assert_equal "Author", essay.writer_type
687
-
688
- # should update when assigning a new record
689
- essay = Essay.new
690
- writer = Author.new
691
- essay.writer = writer
692
- assert_equal "Author", essay.writer_type
693
- end
694
-
695
- def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records
696
- sponsor = Sponsor.new
697
- saved_member = Member.create
698
- new_member = Member.new
699
-
700
- sponsor.sponsorable = saved_member
701
- assert_equal saved_member.id, sponsor.sponsorable_id
702
-
703
- sponsor.sponsorable = new_member
704
- assert_nil sponsor.sponsorable_id
705
- end
706
-
707
- def test_assignment_updates_foreign_id_field_for_new_and_saved_records
708
- client = Client.new
709
- saved_firm = Firm.create :name => "Saved"
710
- new_firm = Firm.new
711
-
712
- client.firm = saved_firm
713
- assert_equal saved_firm.id, client.client_of
714
-
715
- client.firm = new_firm
716
- assert_nil client.client_of
717
- end
718
-
719
- def test_polymorphic_assignment_with_primary_key_updates_foreign_id_field_for_new_and_saved_records
720
- essay = Essay.new
721
- saved_writer = Author.create(:name => "David")
722
- new_writer = Author.new
723
-
724
- essay.writer = saved_writer
725
- assert_equal saved_writer.name, essay.writer_id
726
-
727
- essay.writer = new_writer
728
- assert_nil essay.writer_id
729
- end
730
-
731
- def test_polymorphic_assignment_with_nil
732
- essay = Essay.new
733
- assert_nil essay.writer_id
734
- assert_nil essay.writer_type
735
-
736
- essay.writer_id = 1
737
- essay.writer_type = 'Author'
738
-
739
- essay.writer = nil
740
- assert_nil essay.writer_id
741
- assert_nil essay.writer_type
742
- end
743
-
744
- def test_belongs_to_proxy_should_not_respond_to_private_methods
745
- assert_raise(NoMethodError) { companies(:first_firm).private_method }
746
- assert_raise(NoMethodError) { companies(:second_client).firm.private_method }
747
- end
748
-
749
- def test_belongs_to_proxy_should_respond_to_private_methods_via_send
750
- companies(:first_firm).send(:private_method)
751
- companies(:second_client).firm.send(:private_method)
752
- end
753
-
754
- def test_save_of_record_with_loaded_belongs_to
755
- @account = companies(:first_firm).account
756
-
757
- assert_nothing_raised do
758
- Account.find(@account.id).save!
759
- Account.all.merge!(:includes => :firm).find(@account.id).save!
760
- end
761
-
762
- @account.firm.delete
763
-
764
- assert_nothing_raised do
765
- Account.find(@account.id).save!
766
- Account.all.merge!(:includes => :firm).find(@account.id).save!
767
- end
768
- end
769
-
770
- def test_dependent_delete_and_destroy_with_belongs_to
771
- AuthorAddress.destroyed_author_address_ids.clear
772
-
773
- author_address = author_addresses(:david_address)
774
- author_address_extra = author_addresses(:david_address_extra)
775
- assert_equal [], AuthorAddress.destroyed_author_address_ids
776
-
777
- assert_difference "AuthorAddress.count", -2 do
778
- authors(:david).destroy
779
- end
780
-
781
- assert_equal [], AuthorAddress.where(id: [author_address.id, author_address_extra.id])
782
- assert_equal [author_address.id], AuthorAddress.destroyed_author_address_ids
783
- end
784
-
785
- def test_belongs_to_invalid_dependent_option_raises_exception
786
- error = assert_raise ArgumentError do
787
- Class.new(Author).belongs_to :special_author_address, :dependent => :nullify
788
- end
789
- assert_equal error.message, 'The :dependent option must be one of [:destroy, :delete], but is :nullify'
790
- end
791
-
792
- def test_attributes_are_being_set_when_initialized_from_belongs_to_association_with_where_clause
793
- new_firm = accounts(:signals37).build_firm(:name => 'Apple')
794
- assert_equal new_firm.name, "Apple"
795
- end
796
-
797
- def test_attributes_are_set_without_error_when_initialized_from_belongs_to_association_with_array_in_where_clause
798
- new_account = Account.where(:credit_limit => [ 50, 60 ]).new
799
- assert_nil new_account.credit_limit
800
- end
801
-
802
- def test_reassigning_the_parent_id_updates_the_object
803
- client = companies(:second_client)
804
-
805
- client.firm
806
- client.firm_with_condition
807
- firm_proxy = client.send(:association_instance_get, :firm)
808
- firm_with_condition_proxy = client.send(:association_instance_get, :firm_with_condition)
809
-
810
- assert !firm_proxy.stale_target?
811
- assert !firm_with_condition_proxy.stale_target?
812
- assert_equal companies(:first_firm), client.firm
813
- assert_equal companies(:first_firm), client.firm_with_condition
814
-
815
- client.client_of = companies(:another_firm).id
816
-
817
- assert firm_proxy.stale_target?
818
- assert firm_with_condition_proxy.stale_target?
819
- assert_equal companies(:another_firm), client.firm
820
- assert_equal companies(:another_firm), client.firm_with_condition
821
- end
822
-
823
- def test_polymorphic_reassignment_of_associated_id_updates_the_object
824
- sponsor = sponsors(:moustache_club_sponsor_for_groucho)
825
-
826
- sponsor.sponsorable
827
- proxy = sponsor.send(:association_instance_get, :sponsorable)
828
-
829
- assert !proxy.stale_target?
830
- assert_equal members(:groucho), sponsor.sponsorable
831
-
832
- sponsor.sponsorable_id = members(:some_other_guy).id
833
-
834
- assert proxy.stale_target?
835
- assert_equal members(:some_other_guy), sponsor.sponsorable
836
- end
837
-
838
- def test_polymorphic_reassignment_of_associated_type_updates_the_object
839
- sponsor = sponsors(:moustache_club_sponsor_for_groucho)
840
-
841
- sponsor.sponsorable
842
- proxy = sponsor.send(:association_instance_get, :sponsorable)
843
-
844
- assert !proxy.stale_target?
845
- assert_equal members(:groucho), sponsor.sponsorable
846
-
847
- sponsor.sponsorable_type = 'Firm'
848
-
849
- assert proxy.stale_target?
850
- assert_equal companies(:first_firm), sponsor.sponsorable
851
- end
852
-
853
- def test_reloading_association_with_key_change
854
- client = companies(:second_client)
855
- firm = client.association(:firm)
856
-
857
- client.firm = companies(:another_firm)
858
- firm.reload
859
- assert_equal companies(:another_firm), firm.target
860
-
861
- client.client_of = companies(:first_firm).id
862
- firm.reload
863
- assert_equal companies(:first_firm), firm.target
864
- end
865
-
866
- def test_polymorphic_counter_cache
867
- tagging = taggings(:welcome_general)
868
- post = posts(:welcome)
869
- comment = comments(:greetings)
870
-
871
- assert_difference lambda { post.reload.tags_count }, -1 do
872
- assert_difference 'comment.reload.tags_count', +1 do
873
- tagging.taggable = comment
874
- end
875
- end
876
- end
877
-
878
- def test_polymorphic_with_custom_foreign_type
879
- sponsor = sponsors(:moustache_club_sponsor_for_groucho)
880
- groucho = members(:groucho)
881
- other = members(:some_other_guy)
882
-
883
- assert_equal groucho, sponsor.sponsorable
884
- assert_equal groucho, sponsor.thing
885
-
886
- sponsor.thing = other
887
-
888
- assert_equal other, sponsor.sponsorable
889
- assert_equal other, sponsor.thing
890
-
891
- sponsor.sponsorable = groucho
892
-
893
- assert_equal groucho, sponsor.sponsorable
894
- assert_equal groucho, sponsor.thing
895
- end
896
-
897
- def test_build_with_conditions
898
- client = companies(:second_client)
899
- firm = client.build_bob_firm
900
-
901
- assert_equal "Bob", firm.name
902
- end
903
-
904
- def test_create_with_conditions
905
- client = companies(:second_client)
906
- firm = client.create_bob_firm
907
-
908
- assert_equal "Bob", firm.name
909
- end
910
-
911
- def test_create_bang_with_conditions
912
- client = companies(:second_client)
913
- firm = client.create_bob_firm!
914
-
915
- assert_equal "Bob", firm.name
916
- end
917
-
918
- def test_build_with_block
919
- client = Client.create(:name => 'Client Company')
920
-
921
- firm = client.build_firm{ |f| f.name = 'Agency Company' }
922
- assert_equal 'Agency Company', firm.name
923
- end
924
-
925
- def test_create_with_block
926
- client = Client.create(:name => 'Client Company')
927
-
928
- firm = client.create_firm{ |f| f.name = 'Agency Company' }
929
- assert_equal 'Agency Company', firm.name
930
- end
931
-
932
- def test_create_bang_with_block
933
- client = Client.create(:name => 'Client Company')
934
-
935
- firm = client.create_firm!{ |f| f.name = 'Agency Company' }
936
- assert_equal 'Agency Company', firm.name
937
- end
938
-
939
- def test_should_set_foreign_key_on_create_association
940
- client = Client.create! :name => "fuu"
941
-
942
- firm = client.create_firm :name => "baa"
943
- assert_equal firm.id, client.client_of
944
- end
945
-
946
- def test_should_set_foreign_key_on_create_association!
947
- client = Client.create! :name => "fuu"
948
-
949
- firm = client.create_firm! :name => "baa"
950
- assert_equal firm.id, client.client_of
951
- end
952
-
953
- def test_self_referential_belongs_to_with_counter_cache_assigning_nil
954
- comment = Comment.create! :post => posts(:thinking), :body => "fuu"
955
- comment.parent = nil
956
- comment.save!
957
-
958
- assert_equal nil, comment.reload.parent
959
- assert_equal 0, comments(:greetings).reload.children_count
960
- end
961
-
962
- def test_belongs_to_with_id_assigning
963
- post = posts(:welcome)
964
- comment = Comment.create! body: "foo", post: post
965
- parent = comments(:greetings)
966
- assert_equal 0, parent.reload.children_count
967
- comment.parent_id = parent.id
968
-
969
- comment.save!
970
- assert_equal 1, parent.reload.children_count
971
- end
972
-
973
- def test_polymorphic_with_custom_primary_key
974
- toy = Toy.create!
975
- sponsor = Sponsor.create!(:sponsorable => toy)
976
-
977
- assert_equal toy, sponsor.reload.sponsorable
978
- end
979
-
980
- test "stale tracking doesn't care about the type" do
981
- apple = Firm.create("name" => "Apple")
982
- citibank = Account.create("credit_limit" => 10)
983
-
984
- citibank.firm_id = apple.id
985
- citibank.firm # load it
986
-
987
- citibank.firm_id = apple.id.to_s
988
-
989
- assert !citibank.association(:firm).stale_target?
990
- end
991
-
992
- def test_reflect_the_most_recent_change
993
- author1, author2 = Author.limit(2)
994
- post = Post.new(:title => "foo", :body=> "bar")
995
-
996
- post.author = author1
997
- post.author_id = author2.id
998
-
999
- assert post.save
1000
- assert_equal post.author_id, author2.id
1001
- end
1002
-
1003
- test 'dangerous association name raises ArgumentError' do
1004
- [:errors, 'errors', :save, 'save'].each do |name|
1005
- assert_raises(ArgumentError, "Association #{name} should not be allowed") do
1006
- Class.new(ActiveRecord::Base) do
1007
- belongs_to name
1008
- end
1009
- end
1010
- end
1011
- end
1012
-
1013
- test 'belongs_to works with model called Record' do
1014
- record = Record.create!
1015
- Column.create! record: record
1016
- assert_equal 1, Column.count
1017
- end
1018
- end
1019
-
1020
- class BelongsToWithForeignKeyTest < ActiveRecord::TestCase
1021
- fixtures :authors, :author_addresses
1022
-
1023
- def test_destroy_linked_models
1024
- address = AuthorAddress.create!
1025
- author = Author.create! name: "Author", author_address_id: address.id
1026
-
1027
- author.destroy!
1028
- end
1029
- end
1
+ require 'cases/helper'
2
+ require 'models/developer'
3
+ require 'models/project'
4
+ require 'models/company'
5
+ require 'models/topic'
6
+ require 'models/reply'
7
+ require 'models/computer'
8
+ require 'models/post'
9
+ require 'models/author'
10
+ require 'models/tag'
11
+ require 'models/tagging'
12
+ require 'models/comment'
13
+ require 'models/sponsor'
14
+ require 'models/member'
15
+ require 'models/essay'
16
+ require 'models/toy'
17
+ require 'models/invoice'
18
+ require 'models/line_item'
19
+ require 'models/column'
20
+ require 'models/record'
21
+ require 'models/admin'
22
+ require 'models/admin/user'
23
+ require 'models/ship'
24
+ require 'models/treasure'
25
+ require 'models/parrot'
26
+
27
+ class BelongsToAssociationsTest < ActiveRecord::TestCase
28
+ fixtures :accounts, :companies, :developers, :projects, :topics,
29
+ :developers_projects, :computers, :authors, :author_addresses,
30
+ :posts, :tags, :taggings, :comments, :sponsors, :members
31
+
32
+ def test_belongs_to
33
+ firm = Client.find(3).firm
34
+ assert_not_nil firm
35
+ assert_equal companies(:first_firm).name, firm.name
36
+ end
37
+
38
+ def test_missing_attribute_error_is_raised_when_no_foreign_key_attribute
39
+ assert_raises(ActiveModel::MissingAttributeError) { Client.select(:id).first.firm }
40
+ end
41
+
42
+ def test_belongs_to_does_not_use_order_by
43
+ ActiveRecord::SQLCounter.clear_log
44
+ Client.find(3).firm
45
+ ensure
46
+ assert ActiveRecord::SQLCounter.log_all.all? { |sql| /order by/i !~ sql }, 'ORDER BY was used in the query'
47
+ end
48
+
49
+ def test_belongs_to_with_primary_key
50
+ client = Client.create(:name => "Primary key client", :firm_name => companies(:first_firm).name)
51
+ assert_equal companies(:first_firm).name, client.firm_with_primary_key.name
52
+ end
53
+
54
+ def test_belongs_to_with_primary_key_joins_on_correct_column
55
+ sql = Client.joins(:firm_with_primary_key).to_sql
56
+ if current_adapter?(:Mysql2Adapter)
57
+ assert_no_match(/`firm_with_primary_keys_companies`\.`id`/, sql)
58
+ assert_match(/`firm_with_primary_keys_companies`\.`name`/, sql)
59
+ elsif current_adapter?(:OracleAdapter)
60
+ # on Oracle aliases are truncated to 30 characters and are quoted in uppercase
61
+ assert_no_match(/"firm_with_primary_keys_compani"\."id"/i, sql)
62
+ assert_match(/"firm_with_primary_keys_compani"\."name"/i, sql)
63
+ elsif current_adapter?(:IBM_DBAdapter)
64
+ # Quoting of column names is not necessary for IBM_DB
65
+ assert_no_match(/firm_with_primary_keys_companies\.id/i, sql)
66
+ assert_match(/firm_with_primary_keys_companies\.name/i, sql)
67
+ else
68
+ assert_no_match(/"firm_with_primary_keys_companies"\."id"/, sql)
69
+ assert_match(/"firm_with_primary_keys_companies"\."name"/, sql)
70
+ end
71
+ end
72
+
73
+ def test_optional_relation
74
+ original_value = ActiveRecord::Base.belongs_to_required_by_default
75
+ ActiveRecord::Base.belongs_to_required_by_default = true
76
+
77
+ model = Class.new(ActiveRecord::Base) do
78
+ self.table_name = "accounts"
79
+ def self.name; "Temp"; end
80
+ belongs_to :company, optional: true
81
+ end
82
+
83
+ account = model.new
84
+ assert account.valid?
85
+ ensure
86
+ ActiveRecord::Base.belongs_to_required_by_default = original_value
87
+ end
88
+
89
+ def test_not_optional_relation
90
+ original_value = ActiveRecord::Base.belongs_to_required_by_default
91
+ ActiveRecord::Base.belongs_to_required_by_default = true
92
+
93
+ model = Class.new(ActiveRecord::Base) do
94
+ self.table_name = "accounts"
95
+ def self.name; "Temp"; end
96
+ belongs_to :company, optional: false
97
+ end
98
+
99
+ account = model.new
100
+ assert_not account.valid?
101
+ assert_equal [{error: :blank}], account.errors.details[:company]
102
+ ensure
103
+ ActiveRecord::Base.belongs_to_required_by_default = original_value
104
+ end
105
+
106
+ def test_required_belongs_to_config
107
+ original_value = ActiveRecord::Base.belongs_to_required_by_default
108
+ ActiveRecord::Base.belongs_to_required_by_default = true
109
+
110
+ model = Class.new(ActiveRecord::Base) do
111
+ self.table_name = "accounts"
112
+ def self.name; "Temp"; end
113
+ belongs_to :company
114
+ end
115
+
116
+ account = model.new
117
+ assert_not account.valid?
118
+ assert_equal [{error: :blank}], account.errors.details[:company]
119
+ ensure
120
+ ActiveRecord::Base.belongs_to_required_by_default = original_value
121
+ end
122
+
123
+ def test_default_scope_on_relations_is_not_cached
124
+ counter = 0
125
+
126
+ comments = Class.new(ActiveRecord::Base) {
127
+ self.table_name = 'comments'
128
+ self.inheritance_column = 'not_there'
129
+
130
+ posts = Class.new(ActiveRecord::Base) {
131
+ self.table_name = 'posts'
132
+ self.inheritance_column = 'not_there'
133
+
134
+ default_scope -> {
135
+ counter += 1
136
+ where("id = :inc", :inc => counter)
137
+ }
138
+
139
+ has_many :comments, :anonymous_class => comments
140
+ }
141
+ belongs_to :post, :anonymous_class => posts, :inverse_of => false
142
+ }
143
+
144
+ assert_equal 0, counter
145
+ comment = comments.first
146
+ assert_equal 0, counter
147
+ sql = capture_sql { comment.post }
148
+ comment.reload
149
+ assert_not_equal sql, capture_sql { comment.post }
150
+ end
151
+
152
+ def test_proxy_assignment
153
+ account = Account.find(1)
154
+ assert_nothing_raised { account.firm = account.firm }
155
+ end
156
+
157
+ def test_type_mismatch
158
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = 1 }
159
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) }
160
+ end
161
+
162
+ def test_raises_type_mismatch_with_namespaced_class
163
+ assert_nil defined?(Region), "This test requires that there is no top-level Region class"
164
+
165
+ ActiveRecord::Base.connection.instance_eval do
166
+ create_table(:admin_regions) { |t| t.string :name }
167
+ add_column :admin_users, :region_id, :integer
168
+ end
169
+ Admin.const_set "RegionalUser", Class.new(Admin::User) { belongs_to(:region) }
170
+ Admin.const_set "Region", Class.new(ActiveRecord::Base)
171
+
172
+ e = assert_raise(ActiveRecord::AssociationTypeMismatch) {
173
+ Admin::RegionalUser.new(region: 'wrong value')
174
+ }
175
+ assert_match(/^Region\([^)]+\) expected, got String\([^)]+\)$/, e.message)
176
+ ensure
177
+ Admin.send :remove_const, "Region" if Admin.const_defined?("Region")
178
+ Admin.send :remove_const, "RegionalUser" if Admin.const_defined?("RegionalUser")
179
+
180
+ ActiveRecord::Base.connection.instance_eval do
181
+ remove_column :admin_users, :region_id if column_exists?(:admin_users, :region_id)
182
+ drop_table :admin_regions, if_exists: true
183
+ end
184
+ end
185
+
186
+ def test_natural_assignment
187
+ apple = Firm.create("name" => "Apple")
188
+ citibank = Account.create("credit_limit" => 10)
189
+ citibank.firm = apple
190
+ assert_equal apple.id, citibank.firm_id
191
+ end
192
+
193
+ def test_id_assignment
194
+ apple = Firm.create("name" => "Apple")
195
+ citibank = Account.create("credit_limit" => 10)
196
+ citibank.firm_id = apple
197
+ assert_nil citibank.firm_id
198
+ end
199
+
200
+ def test_natural_assignment_with_primary_key
201
+ apple = Firm.create("name" => "Apple")
202
+ citibank = Client.create("name" => "Primary key client")
203
+ citibank.firm_with_primary_key = apple
204
+ assert_equal apple.name, citibank.firm_name
205
+ end
206
+
207
+ def test_eager_loading_with_primary_key
208
+ Firm.create("name" => "Apple")
209
+ Client.create("name" => "Citibank", :firm_name => "Apple")
210
+ citibank_result = Client.all.merge!(:where => {:name => "Citibank"}, :includes => :firm_with_primary_key).first
211
+ assert citibank_result.association(:firm_with_primary_key).loaded?
212
+ end
213
+
214
+ def test_eager_loading_with_primary_key_as_symbol
215
+ Firm.create("name" => "Apple")
216
+ Client.create("name" => "Citibank", :firm_name => "Apple")
217
+ citibank_result = Client.all.merge!(:where => {:name => "Citibank"}, :includes => :firm_with_primary_key_symbols).first
218
+ assert citibank_result.association(:firm_with_primary_key_symbols).loaded?
219
+ end
220
+
221
+ def test_creating_the_belonging_object
222
+ citibank = Account.create("credit_limit" => 10)
223
+ apple = citibank.create_firm("name" => "Apple")
224
+ assert_equal apple, citibank.firm
225
+ citibank.save
226
+ citibank.reload
227
+ assert_equal apple, citibank.firm
228
+ end
229
+
230
+ def test_creating_the_belonging_object_with_primary_key
231
+ client = Client.create(:name => "Primary key client")
232
+ apple = client.create_firm_with_primary_key("name" => "Apple")
233
+ assert_equal apple, client.firm_with_primary_key
234
+ client.save
235
+ client.reload
236
+ assert_equal apple, client.firm_with_primary_key
237
+ end
238
+
239
+ def test_building_the_belonging_object
240
+ citibank = Account.create("credit_limit" => 10)
241
+ apple = citibank.build_firm("name" => "Apple")
242
+ citibank.save
243
+ assert_equal apple.id, citibank.firm_id
244
+ end
245
+
246
+ def test_building_the_belonging_object_with_implicit_sti_base_class
247
+ account = Account.new
248
+ company = account.build_firm
249
+ assert_kind_of Company, company, "Expected #{company.class} to be a Company"
250
+ end
251
+
252
+ def test_building_the_belonging_object_with_explicit_sti_base_class
253
+ account = Account.new
254
+ company = account.build_firm(:type => "Company")
255
+ assert_kind_of Company, company, "Expected #{company.class} to be a Company"
256
+ end
257
+
258
+ def test_building_the_belonging_object_with_sti_subclass
259
+ account = Account.new
260
+ company = account.build_firm(:type => "Firm")
261
+ assert_kind_of Firm, company, "Expected #{company.class} to be a Firm"
262
+ end
263
+
264
+ def test_building_the_belonging_object_with_an_invalid_type
265
+ account = Account.new
266
+ assert_raise(ActiveRecord::SubclassNotFound) { account.build_firm(:type => "InvalidType") }
267
+ end
268
+
269
+ def test_building_the_belonging_object_with_an_unrelated_type
270
+ account = Account.new
271
+ assert_raise(ActiveRecord::SubclassNotFound) { account.build_firm(:type => "Account") }
272
+ end
273
+
274
+ def test_building_the_belonging_object_with_primary_key
275
+ client = Client.create(:name => "Primary key client")
276
+ apple = client.build_firm_with_primary_key("name" => "Apple")
277
+ client.save
278
+ assert_equal apple.name, client.firm_name
279
+ end
280
+
281
+ def test_create!
282
+ client = Client.create!(:name => "Jimmy")
283
+ account = client.create_account!(:credit_limit => 10)
284
+ assert_equal account, client.account
285
+ assert account.persisted?
286
+ client.save
287
+ client.reload
288
+ assert_equal account, client.account
289
+ end
290
+
291
+ def test_failing_create!
292
+ client = Client.create!(:name => "Jimmy")
293
+ assert_raise(ActiveRecord::RecordInvalid) { client.create_account! }
294
+ assert_not_nil client.account
295
+ assert client.account.new_record?
296
+ end
297
+
298
+ def test_reloading_the_belonging_object
299
+ odegy_account = accounts(:odegy_account)
300
+
301
+ assert_equal "Odegy", odegy_account.firm.name
302
+ Company.where(id: odegy_account.firm_id).update_all(name: "ODEGY")
303
+ assert_equal "Odegy", odegy_account.firm.name
304
+
305
+ assert_equal "ODEGY", odegy_account.reload_firm.name
306
+ end
307
+
308
+ def test_natural_assignment_to_nil
309
+ client = Client.find(3)
310
+ client.firm = nil
311
+ client.save
312
+ client.association(:firm).reload
313
+ assert_nil client.firm
314
+ assert_nil client.client_of
315
+ end
316
+
317
+ def test_natural_assignment_to_nil_with_primary_key
318
+ client = Client.create(:name => "Primary key client", :firm_name => companies(:first_firm).name)
319
+ client.firm_with_primary_key = nil
320
+ client.save
321
+ client.association(:firm_with_primary_key).reload
322
+ assert_nil client.firm_with_primary_key
323
+ assert_nil client.client_of
324
+ end
325
+
326
+ def test_with_different_class_name
327
+ assert_equal Company.find(1).name, Company.find(3).firm_with_other_name.name
328
+ assert_not_nil Company.find(3).firm_with_other_name, "Microsoft should have a firm"
329
+ end
330
+
331
+ def test_with_condition
332
+ assert_equal Company.find(1).name, Company.find(3).firm_with_condition.name
333
+ assert_not_nil Company.find(3).firm_with_condition, "Microsoft should have a firm"
334
+ end
335
+
336
+ def test_polymorphic_association_class
337
+ sponsor = Sponsor.new
338
+ assert_nil sponsor.association(:sponsorable).send(:klass)
339
+ sponsor.association(:sponsorable).reload
340
+ assert_nil sponsor.sponsorable
341
+
342
+ sponsor.sponsorable_type = '' # the column doesn't have to be declared NOT NULL
343
+ assert_nil sponsor.association(:sponsorable).send(:klass)
344
+ sponsor.association(:sponsorable).reload
345
+ assert_nil sponsor.sponsorable
346
+
347
+ sponsor.sponsorable = Member.new :name => "Bert"
348
+ assert_equal Member, sponsor.association(:sponsorable).send(:klass)
349
+ assert_equal "members", sponsor.association(:sponsorable).aliased_table_name
350
+ end
351
+
352
+ def test_with_polymorphic_and_condition
353
+ sponsor = Sponsor.create
354
+ member = Member.create :name => "Bert"
355
+ sponsor.sponsorable = member
356
+
357
+ assert_equal member, sponsor.sponsorable
358
+ assert_nil sponsor.sponsorable_with_conditions
359
+ end
360
+
361
+ def test_with_select
362
+ assert_equal 1, Company.find(2).firm_with_select.attributes.size
363
+ assert_equal 1, Company.all.merge!(:includes => :firm_with_select ).find(2).firm_with_select.attributes.size
364
+ end
365
+
366
+ def test_belongs_to_without_counter_cache_option
367
+ # Ship has a conventionally named `treasures_count` column, but the counter_cache
368
+ # option is not given on the association.
369
+ ship = Ship.create(name: 'Countless')
370
+
371
+ assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed unless counter_cache is given on the relation" do
372
+ treasure = Treasure.new(name: 'Gold', ship: ship)
373
+ treasure.save
374
+ end
375
+
376
+ assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed unless counter_cache is given on the relation" do
377
+ treasure = ship.treasures.first
378
+ treasure.destroy
379
+ end
380
+ end
381
+
382
+ def test_belongs_to_counter
383
+ debate = Topic.create("title" => "debate")
384
+ assert_equal 0, debate.read_attribute("replies_count"), "No replies yet"
385
+
386
+ trash = debate.replies.create("title" => "blah!", "content" => "world around!")
387
+ assert_equal 1, Topic.find(debate.id).read_attribute("replies_count"), "First reply created"
388
+
389
+ trash.destroy
390
+ assert_equal 0, Topic.find(debate.id).read_attribute("replies_count"), "First reply deleted"
391
+ end
392
+
393
+ def test_belongs_to_counter_with_assigning_nil
394
+ post = Post.find(1)
395
+ comment = Comment.find(1)
396
+
397
+ assert_equal post.id, comment.post_id
398
+ assert_equal 2, Post.find(post.id).comments.size
399
+
400
+ comment.post = nil
401
+
402
+ assert_equal 1, Post.find(post.id).comments.size
403
+ end
404
+
405
+ def test_belongs_to_with_primary_key_counter
406
+ debate = Topic.create("title" => "debate")
407
+ debate2 = Topic.create("title" => "debate2")
408
+ reply = Reply.create("title" => "blah!", "content" => "world around!", "parent_title" => "debate")
409
+
410
+ assert_equal 1, debate.reload.replies_count
411
+ assert_equal 0, debate2.reload.replies_count
412
+
413
+ reply.topic_with_primary_key = debate2
414
+
415
+ assert_equal 0, debate.reload.replies_count
416
+ assert_equal 1, debate2.reload.replies_count
417
+
418
+ reply.topic_with_primary_key = nil
419
+
420
+ assert_equal 0, debate.reload.replies_count
421
+ assert_equal 0, debate2.reload.replies_count
422
+ end
423
+
424
+ def test_belongs_to_counter_with_reassigning
425
+ topic1 = Topic.create("title" => "t1")
426
+ topic2 = Topic.create("title" => "t2")
427
+ reply1 = Reply.new("title" => "r1", "content" => "r1")
428
+ reply1.topic = topic1
429
+
430
+ assert reply1.save
431
+ assert_equal 1, Topic.find(topic1.id).replies.size
432
+ assert_equal 0, Topic.find(topic2.id).replies.size
433
+
434
+ reply1.topic = Topic.find(topic2.id)
435
+
436
+ assert_no_queries do
437
+ reply1.topic = topic2
438
+ end
439
+
440
+ assert reply1.save
441
+ assert_equal 0, Topic.find(topic1.id).replies.size
442
+ assert_equal 1, Topic.find(topic2.id).replies.size
443
+
444
+ reply1.topic = nil
445
+
446
+ assert_equal 0, Topic.find(topic1.id).replies.size
447
+ assert_equal 0, Topic.find(topic2.id).replies.size
448
+
449
+ reply1.topic = topic1
450
+
451
+ assert_equal 1, Topic.find(topic1.id).replies.size
452
+ assert_equal 0, Topic.find(topic2.id).replies.size
453
+
454
+ reply1.destroy
455
+
456
+ assert_equal 0, Topic.find(topic1.id).replies.size
457
+ assert_equal 0, Topic.find(topic2.id).replies.size
458
+ end
459
+
460
+ def test_belongs_to_reassign_with_namespaced_models_and_counters
461
+ topic1 = Web::Topic.create("title" => "t1")
462
+ topic2 = Web::Topic.create("title" => "t2")
463
+ reply1 = Web::Reply.new("title" => "r1", "content" => "r1")
464
+ reply1.topic = topic1
465
+
466
+ assert reply1.save
467
+ assert_equal 1, Web::Topic.find(topic1.id).replies.size
468
+ assert_equal 0, Web::Topic.find(topic2.id).replies.size
469
+
470
+ reply1.topic = Web::Topic.find(topic2.id)
471
+
472
+ assert reply1.save
473
+ assert_equal 0, Web::Topic.find(topic1.id).replies.size
474
+ assert_equal 1, Web::Topic.find(topic2.id).replies.size
475
+ end
476
+
477
+ def test_belongs_to_counter_after_save
478
+ topic = Topic.create!(:title => "monday night")
479
+ topic.replies.create!(:title => "re: monday night", :content => "football")
480
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
481
+
482
+ topic.save!
483
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
484
+ end
485
+
486
+ def test_belongs_to_with_touch_option_on_touch
487
+ line_item = LineItem.create!
488
+ Invoice.create!(line_items: [line_item])
489
+
490
+ assert_queries(1) { line_item.touch }
491
+ end
492
+
493
+ def test_belongs_to_with_touch_on_multiple_records
494
+ line_item = LineItem.create!(amount: 1)
495
+ line_item2 = LineItem.create!(amount: 2)
496
+ Invoice.create!(line_items: [line_item, line_item2])
497
+
498
+ assert_queries(1) do
499
+ LineItem.transaction do
500
+ line_item.touch
501
+ line_item2.touch
502
+ end
503
+ end
504
+
505
+ assert_queries(2) do
506
+ line_item.touch
507
+ line_item2.touch
508
+ end
509
+ end
510
+
511
+ def test_belongs_to_with_touch_option_on_touch_without_updated_at_attributes
512
+ assert_not LineItem.column_names.include?("updated_at")
513
+
514
+ line_item = LineItem.create!
515
+ invoice = Invoice.create!(line_items: [line_item])
516
+ initial = invoice.updated_at
517
+ travel(1.second) do
518
+ line_item.touch
519
+ end
520
+
521
+ assert_not_equal initial, invoice.reload.updated_at
522
+ end
523
+
524
+ def test_belongs_to_with_touch_option_on_touch_and_removed_parent
525
+ line_item = LineItem.create!
526
+ Invoice.create!(line_items: [line_item])
527
+
528
+ line_item.invoice = nil
529
+
530
+ assert_queries(2) { line_item.touch }
531
+ end
532
+
533
+ def test_belongs_to_with_touch_option_on_update
534
+ line_item = LineItem.create!
535
+ Invoice.create!(line_items: [line_item])
536
+
537
+ assert_queries(2) { line_item.update amount: 10 }
538
+ end
539
+
540
+ def test_belongs_to_with_touch_option_on_empty_update
541
+ line_item = LineItem.create!
542
+ Invoice.create!(line_items: [line_item])
543
+
544
+ assert_queries(0) { line_item.save }
545
+ end
546
+
547
+ def test_belongs_to_with_touch_option_on_destroy
548
+ line_item = LineItem.create!
549
+ Invoice.create!(line_items: [line_item])
550
+
551
+ assert_queries(2) { line_item.destroy }
552
+ end
553
+
554
+ def test_belongs_to_with_touch_option_on_destroy_with_destroyed_parent
555
+ line_item = LineItem.create!
556
+ invoice = Invoice.create!(line_items: [line_item])
557
+ invoice.destroy
558
+
559
+ assert_queries(1) { line_item.destroy }
560
+ end
561
+
562
+ def test_belongs_to_with_touch_option_on_touch_and_reassigned_parent
563
+ line_item = LineItem.create!
564
+ Invoice.create!(line_items: [line_item])
565
+
566
+ line_item.invoice = Invoice.create!
567
+
568
+ assert_queries(3) { line_item.touch }
569
+ end
570
+
571
+ def test_belongs_to_counter_after_update
572
+ topic = Topic.create!(title: "37s")
573
+ topic.replies.create!(title: "re: 37s", content: "rails")
574
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
575
+
576
+ topic.update(title: "37signals")
577
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
578
+ end
579
+
580
+ def test_belongs_to_counter_when_update_columns
581
+ topic = Topic.create!(:title => "37s")
582
+ topic.replies.create!(:title => "re: 37s", :content => "rails")
583
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
584
+
585
+ topic.update_columns(content: "rails is wonderful")
586
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
587
+ end
588
+
589
+ def test_assignment_before_child_saved
590
+ final_cut = Client.new("name" => "Final Cut")
591
+ firm = Firm.find(1)
592
+ final_cut.firm = firm
593
+ assert !final_cut.persisted?
594
+ assert final_cut.save
595
+ assert final_cut.persisted?
596
+ assert firm.persisted?
597
+ assert_equal firm, final_cut.firm
598
+ final_cut.association(:firm).reload
599
+ assert_equal firm, final_cut.firm
600
+ end
601
+
602
+ def test_assignment_before_child_saved_with_primary_key
603
+ final_cut = Client.new("name" => "Final Cut")
604
+ firm = Firm.find(1)
605
+ final_cut.firm_with_primary_key = firm
606
+ assert !final_cut.persisted?
607
+ assert final_cut.save
608
+ assert final_cut.persisted?
609
+ assert firm.persisted?
610
+ assert_equal firm, final_cut.firm_with_primary_key
611
+ final_cut.association(:firm_with_primary_key).reload
612
+ assert_equal firm, final_cut.firm_with_primary_key
613
+ end
614
+
615
+ def test_new_record_with_foreign_key_but_no_object
616
+ client = Client.new("firm_id" => 1)
617
+ # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
618
+ assert_equal Firm.all.merge!(:order => "id").first, client.firm_with_basic_id
619
+ end
620
+
621
+ def test_setting_foreign_key_after_nil_target_loaded
622
+ client = Client.new
623
+ client.firm_with_basic_id
624
+ client.firm_id = 1
625
+
626
+ assert_equal companies(:first_firm), client.firm_with_basic_id
627
+ end
628
+
629
+ def test_polymorphic_setting_foreign_key_after_nil_target_loaded
630
+ sponsor = Sponsor.new
631
+ sponsor.sponsorable
632
+ sponsor.sponsorable_id = 1
633
+ sponsor.sponsorable_type = "Member"
634
+
635
+ assert_equal members(:groucho), sponsor.sponsorable
636
+ end
637
+
638
+ def test_dont_find_target_when_foreign_key_is_null
639
+ tagging = taggings(:thinking_general)
640
+ assert_queries(0) { tagging.super_tag }
641
+ end
642
+
643
+ def test_dont_find_target_when_saving_foreign_key_after_stale_association_loaded
644
+ client = Client.create!(name: "Test client", firm_with_basic_id: Firm.find(1))
645
+ client.firm_id = Firm.create!(name: "Test firm").id
646
+ assert_queries(1) { client.save! }
647
+ end
648
+
649
+ def test_field_name_same_as_foreign_key
650
+ computer = Computer.find(1)
651
+ assert_not_nil computer.developer, ":foreign key == attribute didn't lock up" # '
652
+ end
653
+
654
+ def test_counter_cache
655
+ topic = Topic.create :title => "Zoom-zoom-zoom"
656
+ assert_equal 0, topic[:replies_count]
657
+
658
+ reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
659
+ reply.topic = topic
660
+
661
+ assert_equal 1, topic.reload[:replies_count]
662
+ assert_equal 1, topic.replies.size
663
+
664
+ topic[:replies_count] = 15
665
+ assert_equal 15, topic.replies.size
666
+ end
667
+
668
+ def test_counter_cache_double_destroy
669
+ topic = Topic.create :title => "Zoom-zoom-zoom"
670
+
671
+ 5.times do
672
+ topic.replies.create(:title => "re: zoom", :content => "speedy quick!")
673
+ end
674
+
675
+ assert_equal 5, topic.reload[:replies_count]
676
+ assert_equal 5, topic.replies.size
677
+
678
+ reply = topic.replies.first
679
+
680
+ reply.destroy
681
+ assert_equal 4, topic.reload[:replies_count]
682
+
683
+ reply.destroy
684
+ assert_equal 4, topic.reload[:replies_count]
685
+ assert_equal 4, topic.replies.size
686
+ end
687
+
688
+ def test_concurrent_counter_cache_double_destroy
689
+ topic = Topic.create :title => "Zoom-zoom-zoom"
690
+
691
+ 5.times do
692
+ topic.replies.create(:title => "re: zoom", :content => "speedy quick!")
693
+ end
694
+
695
+ assert_equal 5, topic.reload[:replies_count]
696
+ assert_equal 5, topic.replies.size
697
+
698
+ reply = topic.replies.first
699
+ reply_clone = Reply.find(reply.id)
700
+
701
+ reply.destroy
702
+ assert_equal 4, topic.reload[:replies_count]
703
+
704
+ reply_clone.destroy
705
+ assert_equal 4, topic.reload[:replies_count]
706
+ assert_equal 4, topic.replies.size
707
+ end
708
+
709
+ def test_custom_counter_cache
710
+ reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
711
+ assert_equal 0, reply[:replies_count]
712
+
713
+ silly = SillyReply.create(:title => "gaga", :content => "boo-boo")
714
+ silly.reply = reply
715
+
716
+ assert_equal 1, reply.reload[:replies_count]
717
+ assert_equal 1, reply.replies.size
718
+
719
+ reply[:replies_count] = 17
720
+ assert_equal 17, reply.replies.size
721
+ end
722
+
723
+ def test_replace_counter_cache
724
+ topic = Topic.create(title: "Zoom-zoom-zoom")
725
+ reply = Reply.create(title: "re: zoom", content: "speedy quick!")
726
+
727
+ reply.topic = topic
728
+ reply.save
729
+ topic.reload
730
+
731
+ assert_equal 1, topic.replies_count
732
+ end
733
+
734
+ def test_association_assignment_sticks
735
+ post = Post.first
736
+
737
+ author1, author2 = Author.all.merge!(:limit => 2).to_a
738
+ assert_not_nil author1
739
+ assert_not_nil author2
740
+
741
+ # make sure the association is loaded
742
+ post.author
743
+
744
+ # set the association by id, directly
745
+ post.author_id = author2.id
746
+
747
+ # save and reload
748
+ post.save!
749
+ post.reload
750
+
751
+ # the author id of the post should be the id we set
752
+ assert_equal post.author_id, author2.id
753
+ end
754
+
755
+ def test_cant_save_readonly_association
756
+ assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_client).readonly_firm.save! }
757
+ assert companies(:first_client).readonly_firm.readonly?
758
+ end
759
+
760
+ def test_polymorphic_assignment_foreign_key_type_string
761
+ comment = Comment.first
762
+ comment.author = Author.first
763
+ comment.resource = Member.first
764
+ comment.save
765
+
766
+ assert_equal Comment.all.to_a,
767
+ Comment.includes(:author).to_a
768
+
769
+ assert_equal Comment.all.to_a,
770
+ Comment.includes(:resource).to_a
771
+ end
772
+
773
+ def test_polymorphic_assignment_foreign_type_field_updating
774
+ # should update when assigning a saved record
775
+ sponsor = Sponsor.new
776
+ member = Member.create
777
+ sponsor.sponsorable = member
778
+ assert_equal "Member", sponsor.sponsorable_type
779
+
780
+ # should update when assigning a new record
781
+ sponsor = Sponsor.new
782
+ member = Member.new
783
+ sponsor.sponsorable = member
784
+ assert_equal "Member", sponsor.sponsorable_type
785
+ end
786
+
787
+ def test_polymorphic_assignment_with_primary_key_foreign_type_field_updating
788
+ # should update when assigning a saved record
789
+ essay = Essay.new
790
+ writer = Author.create(:name => "David")
791
+ essay.writer = writer
792
+ assert_equal "Author", essay.writer_type
793
+
794
+ # should update when assigning a new record
795
+ essay = Essay.new
796
+ writer = Author.new
797
+ essay.writer = writer
798
+ assert_equal "Author", essay.writer_type
799
+ end
800
+
801
+ def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records
802
+ sponsor = Sponsor.new
803
+ saved_member = Member.create
804
+ new_member = Member.new
805
+
806
+ sponsor.sponsorable = saved_member
807
+ assert_equal saved_member.id, sponsor.sponsorable_id
808
+
809
+ sponsor.sponsorable = new_member
810
+ assert_nil sponsor.sponsorable_id
811
+ end
812
+
813
+ def test_assignment_updates_foreign_id_field_for_new_and_saved_records
814
+ client = Client.new
815
+ saved_firm = Firm.create :name => "Saved"
816
+ new_firm = Firm.new
817
+
818
+ client.firm = saved_firm
819
+ assert_equal saved_firm.id, client.client_of
820
+
821
+ client.firm = new_firm
822
+ assert_nil client.client_of
823
+ end
824
+
825
+ def test_polymorphic_assignment_with_primary_key_updates_foreign_id_field_for_new_and_saved_records
826
+ essay = Essay.new
827
+ saved_writer = Author.create(:name => "David")
828
+ new_writer = Author.new
829
+
830
+ essay.writer = saved_writer
831
+ assert_equal saved_writer.name, essay.writer_id
832
+
833
+ essay.writer = new_writer
834
+ assert_nil essay.writer_id
835
+ end
836
+
837
+ def test_polymorphic_assignment_with_nil
838
+ essay = Essay.new
839
+ assert_nil essay.writer_id
840
+ assert_nil essay.writer_type
841
+
842
+ essay.writer_id = 1
843
+ essay.writer_type = 'Author'
844
+
845
+ essay.writer = nil
846
+ assert_nil essay.writer_id
847
+ assert_nil essay.writer_type
848
+ end
849
+
850
+ def test_belongs_to_proxy_should_not_respond_to_private_methods
851
+ assert_raise(NoMethodError) { companies(:first_firm).private_method }
852
+ assert_raise(NoMethodError) { companies(:second_client).firm.private_method }
853
+ end
854
+
855
+ def test_belongs_to_proxy_should_respond_to_private_methods_via_send
856
+ companies(:first_firm).send(:private_method)
857
+ companies(:second_client).firm.send(:private_method)
858
+ end
859
+
860
+ def test_save_of_record_with_loaded_belongs_to
861
+ @account = companies(:first_firm).account
862
+
863
+ assert_nothing_raised do
864
+ Account.find(@account.id).save!
865
+ Account.all.merge!(:includes => :firm).find(@account.id).save!
866
+ end
867
+
868
+ @account.firm.delete
869
+
870
+ assert_nothing_raised do
871
+ Account.find(@account.id).save!
872
+ Account.all.merge!(:includes => :firm).find(@account.id).save!
873
+ end
874
+ end
875
+
876
+ def test_dependent_delete_and_destroy_with_belongs_to
877
+ AuthorAddress.destroyed_author_address_ids.clear
878
+
879
+ author_address = author_addresses(:david_address)
880
+ author_address_extra = author_addresses(:david_address_extra)
881
+ assert_equal [], AuthorAddress.destroyed_author_address_ids
882
+
883
+ assert_difference "AuthorAddress.count", -2 do
884
+ authors(:david).destroy
885
+ end
886
+
887
+ assert_equal [], AuthorAddress.where(id: [author_address.id, author_address_extra.id])
888
+ assert_equal [author_address.id], AuthorAddress.destroyed_author_address_ids
889
+ end
890
+
891
+ def test_belongs_to_invalid_dependent_option_raises_exception
892
+ error = assert_raise ArgumentError do
893
+ Class.new(Author).belongs_to :special_author_address, :dependent => :nullify
894
+ end
895
+ assert_equal error.message, 'The :dependent option must be one of [:destroy, :delete], but is :nullify'
896
+ end
897
+
898
+ def test_attributes_are_being_set_when_initialized_from_belongs_to_association_with_where_clause
899
+ new_firm = accounts(:signals37).build_firm(:name => 'Apple')
900
+ assert_equal new_firm.name, "Apple"
901
+ end
902
+
903
+ def test_attributes_are_set_without_error_when_initialized_from_belongs_to_association_with_array_in_where_clause
904
+ new_account = Account.where(:credit_limit => [ 50, 60 ]).new
905
+ assert_nil new_account.credit_limit
906
+ end
907
+
908
+ def test_reassigning_the_parent_id_updates_the_object
909
+ client = companies(:second_client)
910
+
911
+ client.firm
912
+ client.firm_with_condition
913
+ firm_proxy = client.send(:association_instance_get, :firm)
914
+ firm_with_condition_proxy = client.send(:association_instance_get, :firm_with_condition)
915
+
916
+ assert !firm_proxy.stale_target?
917
+ assert !firm_with_condition_proxy.stale_target?
918
+ assert_equal companies(:first_firm), client.firm
919
+ assert_equal companies(:first_firm), client.firm_with_condition
920
+
921
+ client.client_of = companies(:another_firm).id
922
+
923
+ assert firm_proxy.stale_target?
924
+ assert firm_with_condition_proxy.stale_target?
925
+ assert_equal companies(:another_firm), client.firm
926
+ assert_equal companies(:another_firm), client.firm_with_condition
927
+ end
928
+
929
+ def test_polymorphic_reassignment_of_associated_id_updates_the_object
930
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
931
+
932
+ sponsor.sponsorable
933
+ proxy = sponsor.send(:association_instance_get, :sponsorable)
934
+
935
+ assert !proxy.stale_target?
936
+ assert_equal members(:groucho), sponsor.sponsorable
937
+
938
+ sponsor.sponsorable_id = members(:some_other_guy).id
939
+
940
+ assert proxy.stale_target?
941
+ assert_equal members(:some_other_guy), sponsor.sponsorable
942
+ end
943
+
944
+ def test_polymorphic_reassignment_of_associated_type_updates_the_object
945
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
946
+
947
+ sponsor.sponsorable
948
+ proxy = sponsor.send(:association_instance_get, :sponsorable)
949
+
950
+ assert !proxy.stale_target?
951
+ assert_equal members(:groucho), sponsor.sponsorable
952
+
953
+ sponsor.sponsorable_type = 'Firm'
954
+
955
+ assert proxy.stale_target?
956
+ assert_equal companies(:first_firm), sponsor.sponsorable
957
+ end
958
+
959
+ def test_reloading_association_with_key_change
960
+ client = companies(:second_client)
961
+ firm = client.association(:firm)
962
+
963
+ client.firm = companies(:another_firm)
964
+ firm.reload
965
+ assert_equal companies(:another_firm), firm.target
966
+
967
+ client.client_of = companies(:first_firm).id
968
+ firm.reload
969
+ assert_equal companies(:first_firm), firm.target
970
+ end
971
+
972
+ def test_polymorphic_counter_cache
973
+ tagging = taggings(:welcome_general)
974
+ post = posts(:welcome)
975
+ comment = comments(:greetings)
976
+
977
+ assert_difference lambda { post.reload.tags_count }, -1 do
978
+ assert_difference 'comment.reload.tags_count', +1 do
979
+ tagging.taggable = comment
980
+ end
981
+ end
982
+ end
983
+
984
+ def test_polymorphic_with_custom_foreign_type
985
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
986
+ groucho = members(:groucho)
987
+ other = members(:some_other_guy)
988
+
989
+ assert_equal groucho, sponsor.sponsorable
990
+ assert_equal groucho, sponsor.thing
991
+
992
+ sponsor.thing = other
993
+
994
+ assert_equal other, sponsor.sponsorable
995
+ assert_equal other, sponsor.thing
996
+
997
+ sponsor.sponsorable = groucho
998
+
999
+ assert_equal groucho, sponsor.sponsorable
1000
+ assert_equal groucho, sponsor.thing
1001
+ end
1002
+
1003
+ def test_build_with_conditions
1004
+ client = companies(:second_client)
1005
+ firm = client.build_bob_firm
1006
+
1007
+ assert_equal "Bob", firm.name
1008
+ end
1009
+
1010
+ def test_create_with_conditions
1011
+ client = companies(:second_client)
1012
+ firm = client.create_bob_firm
1013
+
1014
+ assert_equal "Bob", firm.name
1015
+ end
1016
+
1017
+ def test_create_bang_with_conditions
1018
+ client = companies(:second_client)
1019
+ firm = client.create_bob_firm!
1020
+
1021
+ assert_equal "Bob", firm.name
1022
+ end
1023
+
1024
+ def test_build_with_block
1025
+ client = Client.create(:name => 'Client Company')
1026
+
1027
+ firm = client.build_firm{ |f| f.name = 'Agency Company' }
1028
+ assert_equal 'Agency Company', firm.name
1029
+ end
1030
+
1031
+ def test_create_with_block
1032
+ client = Client.create(:name => 'Client Company')
1033
+
1034
+ firm = client.create_firm{ |f| f.name = 'Agency Company' }
1035
+ assert_equal 'Agency Company', firm.name
1036
+ end
1037
+
1038
+ def test_create_bang_with_block
1039
+ client = Client.create(:name => 'Client Company')
1040
+
1041
+ firm = client.create_firm!{ |f| f.name = 'Agency Company' }
1042
+ assert_equal 'Agency Company', firm.name
1043
+ end
1044
+
1045
+ def test_should_set_foreign_key_on_create_association
1046
+ client = Client.create! :name => "fuu"
1047
+
1048
+ firm = client.create_firm :name => "baa"
1049
+ assert_equal firm.id, client.client_of
1050
+ end
1051
+
1052
+ def test_should_set_foreign_key_on_create_association!
1053
+ client = Client.create! :name => "fuu"
1054
+
1055
+ firm = client.create_firm! :name => "baa"
1056
+ assert_equal firm.id, client.client_of
1057
+ end
1058
+
1059
+ def test_self_referential_belongs_to_with_counter_cache_assigning_nil
1060
+ comment = Comment.create! :post => posts(:thinking), :body => "fuu"
1061
+ comment.parent = nil
1062
+ comment.save!
1063
+
1064
+ assert_equal nil, comment.reload.parent
1065
+ assert_equal 0, comments(:greetings).reload.children_count
1066
+ end
1067
+
1068
+ def test_belongs_to_with_id_assigning
1069
+ post = posts(:welcome)
1070
+ comment = Comment.create! body: "foo", post: post
1071
+ parent = comments(:greetings)
1072
+ assert_equal 0, parent.reload.children_count
1073
+ comment.parent_id = parent.id
1074
+
1075
+ comment.save!
1076
+ assert_equal 1, parent.reload.children_count
1077
+ end
1078
+
1079
+ def test_polymorphic_with_custom_primary_key
1080
+ toy = Toy.create!
1081
+ sponsor = Sponsor.create!(:sponsorable => toy)
1082
+
1083
+ assert_equal toy, sponsor.reload.sponsorable
1084
+ end
1085
+
1086
+ test "stale tracking doesn't care about the type" do
1087
+ apple = Firm.create("name" => "Apple")
1088
+ citibank = Account.create("credit_limit" => 10)
1089
+
1090
+ citibank.firm_id = apple.id
1091
+ citibank.firm # load it
1092
+
1093
+ citibank.firm_id = apple.id.to_s
1094
+
1095
+ assert !citibank.association(:firm).stale_target?
1096
+ end
1097
+
1098
+ def test_reflect_the_most_recent_change
1099
+ author1, author2 = Author.limit(2)
1100
+ post = Post.new(:title => "foo", :body=> "bar")
1101
+
1102
+ post.author = author1
1103
+ post.author_id = author2.id
1104
+
1105
+ assert post.save
1106
+ assert_equal post.author_id, author2.id
1107
+ end
1108
+
1109
+ test 'dangerous association name raises ArgumentError' do
1110
+ [:errors, 'errors', :save, 'save'].each do |name|
1111
+ assert_raises(ArgumentError, "Association #{name} should not be allowed") do
1112
+ Class.new(ActiveRecord::Base) do
1113
+ belongs_to name
1114
+ end
1115
+ end
1116
+ end
1117
+ end
1118
+
1119
+ test 'belongs_to works with model called Record' do
1120
+ record = Record.create!
1121
+ Column.create! record: record
1122
+ assert_equal 1, Column.count
1123
+ end
1124
+
1125
+ def test_association_force_reload_with_only_true_is_deprecated
1126
+ client = Client.find(3)
1127
+
1128
+ assert_deprecated { client.firm(true) }
1129
+ end
1130
+ end
1131
+
1132
+ class BelongsToWithForeignKeyTest < ActiveRecord::TestCase
1133
+ fixtures :authors, :author_addresses
1134
+
1135
+ def test_destroy_linked_models
1136
+ address = AuthorAddress.create!
1137
+ author = Author.create! name: "Author", author_address_id: address.id
1138
+
1139
+ author.destroy!
1140
+ end
1141
+ end