ibm_db 3.0.0-x86-mingw32 → 3.0.1-x86-mingw32

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