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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,1204 @@
1
+ require "cases/helper"
2
+ require 'models/post'
3
+ require 'models/person'
4
+ require 'models/reference'
5
+ require 'models/job'
6
+ require 'models/reader'
7
+ require 'models/comment'
8
+ require 'models/rating'
9
+ require 'models/tag'
10
+ require 'models/tagging'
11
+ require 'models/author'
12
+ require 'models/owner'
13
+ require 'models/pet'
14
+ require 'models/toy'
15
+ require 'models/contract'
16
+ require 'models/company'
17
+ require 'models/developer'
18
+ require 'models/computer'
19
+ require 'models/subscriber'
20
+ require 'models/book'
21
+ require 'models/subscription'
22
+ require 'models/essay'
23
+ require 'models/category'
24
+ require 'models/categorization'
25
+ require 'models/member'
26
+ require 'models/membership'
27
+ require 'models/club'
28
+ require 'models/organization'
29
+
30
+ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
31
+ fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags,
32
+ :owners, :pets, :toys, :jobs, :references, :companies, :members, :author_addresses,
33
+ :subscribers, :books, :subscriptions, :developers, :categorizations, :essays,
34
+ :categories_posts, :clubs, :memberships, :organizations
35
+
36
+ # Dummies to force column loads so query counts are clean.
37
+ def setup
38
+ Person.create :first_name => 'gummy'
39
+ Reader.create :person_id => 0, :post_id => 0
40
+ end
41
+
42
+ def test_preload_sti_rhs_class
43
+ developers = Developer.includes(:firms).all.to_a
44
+ assert_no_queries do
45
+ developers.each { |d| d.firms }
46
+ end
47
+ end
48
+
49
+ def test_preload_sti_middle_relation
50
+ club = Club.create!(name: 'Aaron cool banana club')
51
+ member1 = Member.create!(name: 'Aaron')
52
+ member2 = Member.create!(name: 'Cat')
53
+
54
+ SuperMembership.create! club: club, member: member1
55
+ CurrentMembership.create! club: club, member: member2
56
+
57
+ club1 = Club.includes(:members).find_by_id club.id
58
+ assert_equal [member1, member2].sort_by(&:id),
59
+ club1.members.sort_by(&:id)
60
+ end
61
+
62
+ def make_model(name)
63
+ Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } }
64
+ end
65
+
66
+ def test_ordered_habtm
67
+ person_prime = Class.new(ActiveRecord::Base) do
68
+ def self.name; 'Person'; end
69
+
70
+ has_many :readers
71
+ has_many :posts, -> { order('posts.id DESC') }, :through => :readers
72
+ end
73
+ posts = person_prime.includes(:posts).first.posts
74
+
75
+ assert_operator posts.length, :>, 1
76
+ posts.each_cons(2) do |left,right|
77
+ assert_operator left.id, :>, right.id
78
+ end
79
+ end
80
+
81
+ def test_singleton_has_many_through
82
+ book = make_model "Book"
83
+ subscription = make_model "Subscription"
84
+ subscriber = make_model "Subscriber"
85
+
86
+ subscriber.primary_key = 'nick'
87
+ subscription.belongs_to :book, anonymous_class: book
88
+ subscription.belongs_to :subscriber, anonymous_class: subscriber
89
+
90
+ book.has_many :subscriptions, anonymous_class: subscription
91
+ book.has_many :subscribers, through: :subscriptions, anonymous_class: subscriber
92
+
93
+ anonbook = book.first
94
+ namebook = Book.find anonbook.id
95
+
96
+ assert_operator anonbook.subscribers.count, :>, 0
97
+ anonbook.subscribers.each do |s|
98
+ assert_instance_of subscriber, s
99
+ end
100
+ assert_equal namebook.subscribers.map(&:id).sort,
101
+ anonbook.subscribers.map(&:id).sort
102
+ end
103
+
104
+ def test_no_pk_join_table_append
105
+ lesson, _, student = make_no_pk_hm_t
106
+
107
+ sicp = lesson.new(:name => "SICP")
108
+ ben = student.new(:name => "Ben Bitdiddle")
109
+ sicp.students << ben
110
+ assert sicp.save!
111
+ end
112
+
113
+ def test_no_pk_join_table_delete
114
+ lesson, lesson_student, student = make_no_pk_hm_t
115
+
116
+ sicp = lesson.new(:name => "SICP")
117
+ ben = student.new(:name => "Ben Bitdiddle")
118
+ louis = student.new(:name => "Louis Reasoner")
119
+ sicp.students << ben
120
+ sicp.students << louis
121
+ assert sicp.save!
122
+
123
+ sicp.students.reload
124
+ assert_operator lesson_student.count, :>=, 2
125
+ assert_no_difference('student.count') do
126
+ assert_difference('lesson_student.count', -2) do
127
+ sicp.students.destroy(*student.all.to_a)
128
+ end
129
+ end
130
+ end
131
+
132
+ def test_no_pk_join_model_callbacks
133
+ lesson, lesson_student, student = make_no_pk_hm_t
134
+
135
+ after_destroy_called = false
136
+ lesson_student.after_destroy do
137
+ after_destroy_called = true
138
+ end
139
+
140
+ sicp = lesson.new(:name => "SICP")
141
+ ben = student.new(:name => "Ben Bitdiddle")
142
+ sicp.students << ben
143
+ assert sicp.save!
144
+
145
+ sicp.students.reload
146
+ sicp.students.destroy(*student.all.to_a)
147
+ assert after_destroy_called, "after destroy should be called"
148
+ end
149
+
150
+ def make_no_pk_hm_t
151
+ lesson = make_model 'Lesson'
152
+ student = make_model 'Student'
153
+
154
+ lesson_student = make_model 'LessonStudent'
155
+ lesson_student.table_name = 'lessons_students'
156
+
157
+ lesson_student.belongs_to :lesson, :anonymous_class => lesson
158
+ lesson_student.belongs_to :student, :anonymous_class => student
159
+ lesson.has_many :lesson_students, :anonymous_class => lesson_student
160
+ lesson.has_many :students, :through => :lesson_students, :anonymous_class => student
161
+ [lesson, lesson_student, student]
162
+ end
163
+
164
+ def test_pk_is_not_required_for_join
165
+ post = Post.includes(:scategories).first
166
+ post2 = Post.includes(:categories).first
167
+
168
+ assert_operator post.categories.length, :>, 0
169
+ assert_equal post2.categories, post.categories
170
+ end
171
+
172
+ def test_include?
173
+ person = Person.new
174
+ post = Post.new
175
+ person.posts << post
176
+ assert person.posts.include?(post)
177
+ end
178
+
179
+ def test_associate_existing
180
+ post = posts(:thinking)
181
+ person = people(:david)
182
+
183
+ assert_queries(1) do
184
+ post.people << person
185
+ end
186
+
187
+ assert_queries(1) do
188
+ assert post.people.include?(person)
189
+ end
190
+
191
+ assert post.reload.people(true).include?(person)
192
+ end
193
+
194
+ def test_delete_all_for_with_dependent_option_destroy
195
+ person = people(:david)
196
+ assert_equal 1, person.jobs_with_dependent_destroy.count
197
+
198
+ assert_no_difference 'Job.count' do
199
+ assert_difference 'Reference.count', -1 do
200
+ person.reload.jobs_with_dependent_destroy.delete_all
201
+ end
202
+ end
203
+ end
204
+
205
+ def test_delete_all_for_with_dependent_option_nullify
206
+ person = people(:david)
207
+ assert_equal 1, person.jobs_with_dependent_nullify.count
208
+
209
+ assert_no_difference 'Job.count' do
210
+ assert_no_difference 'Reference.count' do
211
+ person.reload.jobs_with_dependent_nullify.delete_all
212
+ end
213
+ end
214
+ end
215
+
216
+ def test_delete_all_for_with_dependent_option_delete_all
217
+ person = people(:david)
218
+ assert_equal 1, person.jobs_with_dependent_delete_all.count
219
+
220
+ assert_no_difference 'Job.count' do
221
+ assert_difference 'Reference.count', -1 do
222
+ person.reload.jobs_with_dependent_delete_all.delete_all
223
+ end
224
+ end
225
+ end
226
+
227
+ def test_concat
228
+ person = people(:david)
229
+ post = posts(:thinking)
230
+ post.people.concat [person]
231
+ assert_equal 1, post.people.size
232
+ assert_equal 1, post.people(true).size
233
+ end
234
+
235
+ def test_associate_existing_record_twice_should_add_to_target_twice
236
+ post = posts(:thinking)
237
+ person = people(:david)
238
+
239
+ assert_difference 'post.people.to_a.count', 2 do
240
+ post.people << person
241
+ post.people << person
242
+ end
243
+ end
244
+
245
+ def test_associate_existing_record_twice_should_add_records_twice
246
+ post = posts(:thinking)
247
+ person = people(:david)
248
+
249
+ assert_difference 'post.people.count', 2 do
250
+ post.people << person
251
+ post.people << person
252
+ end
253
+ end
254
+
255
+ def test_add_two_instance_and_then_deleting
256
+ post = posts(:thinking)
257
+ person = people(:david)
258
+
259
+ post.people << person
260
+ post.people << person
261
+
262
+ counts = ['post.people.count', 'post.people.to_a.count', 'post.readers.count', 'post.readers.to_a.count']
263
+ assert_difference counts, -2 do
264
+ post.people.delete(person)
265
+ end
266
+
267
+ assert !post.people.reload.include?(person)
268
+ end
269
+
270
+ def test_associating_new
271
+ assert_queries(1) { posts(:thinking) }
272
+ new_person = nil # so block binding catches it
273
+
274
+ assert_queries(0) do
275
+ new_person = Person.new :first_name => 'bob'
276
+ end
277
+
278
+ # Associating new records always saves them
279
+ # Thus, 1 query for the new person record, 1 query for the new join table record
280
+ assert_queries(2) do
281
+ posts(:thinking).people << new_person
282
+ end
283
+
284
+ assert_queries(1) do
285
+ assert posts(:thinking).people.include?(new_person)
286
+ end
287
+
288
+ assert posts(:thinking).reload.people(true).include?(new_person)
289
+ end
290
+
291
+ def test_associate_new_by_building
292
+ assert_queries(1) { posts(:thinking) }
293
+
294
+ assert_queries(0) do
295
+ posts(:thinking).people.build(:first_name => "Bob")
296
+ posts(:thinking).people.new(:first_name => "Ted")
297
+ end
298
+
299
+ # Should only need to load the association once
300
+ assert_queries(1) do
301
+ assert posts(:thinking).people.collect(&:first_name).include?("Bob")
302
+ assert posts(:thinking).people.collect(&:first_name).include?("Ted")
303
+ end
304
+
305
+ # 2 queries for each new record (1 to save the record itself, 1 for the join model)
306
+ # * 2 new records = 4
307
+ # + 1 query to save the actual post = 5
308
+ assert_queries(5) do
309
+ posts(:thinking).body += '-changed'
310
+ posts(:thinking).save
311
+ end
312
+
313
+ assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Bob")
314
+ assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Ted")
315
+ end
316
+
317
+ def test_build_then_save_with_has_many_inverse
318
+ post = posts(:thinking)
319
+ person = post.people.build(:first_name => "Bob")
320
+ person.save
321
+ post.reload
322
+
323
+ assert post.people.include?(person)
324
+ end
325
+
326
+ def test_build_then_save_with_has_one_inverse
327
+ post = posts(:thinking)
328
+ person = post.single_people.build(:first_name => "Bob")
329
+ person.save
330
+ post.reload
331
+
332
+ assert post.single_people.include?(person)
333
+ end
334
+
335
+ def test_both_parent_ids_set_when_saving_new
336
+ post = Post.new(title: 'Hello', body: 'world')
337
+ person = Person.new(first_name: 'Sean')
338
+
339
+ post.people = [person]
340
+ post.save
341
+
342
+ assert post.id
343
+ assert person.id
344
+ assert_equal post.id, post.readers.first.post_id
345
+ assert_equal person.id, post.readers.first.person_id
346
+ end
347
+
348
+ def test_delete_association
349
+ assert_queries(2){posts(:welcome);people(:michael); }
350
+
351
+ assert_queries(1) do
352
+ posts(:welcome).people.delete(people(:michael))
353
+ end
354
+
355
+ assert_queries(1) do
356
+ assert posts(:welcome).people.empty?
357
+ end
358
+
359
+ assert posts(:welcome).reload.people(true).empty?
360
+ end
361
+
362
+ def test_destroy_association
363
+ assert_no_difference "Person.count" do
364
+ assert_difference "Reader.count", -1 do
365
+ posts(:welcome).people.destroy(people(:michael))
366
+ end
367
+ end
368
+
369
+ assert posts(:welcome).reload.people.empty?
370
+ assert posts(:welcome).people(true).empty?
371
+ end
372
+
373
+ def test_destroy_all
374
+ assert_no_difference "Person.count" do
375
+ assert_difference "Reader.count", -1 do
376
+ posts(:welcome).people.destroy_all
377
+ end
378
+ end
379
+
380
+ assert posts(:welcome).reload.people.empty?
381
+ assert posts(:welcome).people(true).empty?
382
+ end
383
+
384
+ def test_should_raise_exception_for_destroying_mismatching_records
385
+ assert_no_difference ["Person.count", "Reader.count"] do
386
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:welcome).people.destroy(posts(:thinking)) }
387
+ end
388
+ end
389
+
390
+ def test_delete_through_belongs_to_with_dependent_nullify
391
+ Reference.make_comments = true
392
+
393
+ person = people(:michael)
394
+ job = jobs(:magician)
395
+ reference = Reference.where(:job_id => job.id, :person_id => person.id).first
396
+
397
+ assert_no_difference ['Job.count', 'Reference.count'] do
398
+ assert_difference 'person.jobs.count', -1 do
399
+ person.jobs_with_dependent_nullify.delete(job)
400
+ end
401
+ end
402
+
403
+ assert_equal nil, reference.reload.job_id
404
+ ensure
405
+ Reference.make_comments = false
406
+ end
407
+
408
+ def test_delete_through_belongs_to_with_dependent_delete_all
409
+ Reference.make_comments = true
410
+
411
+ person = people(:michael)
412
+ job = jobs(:magician)
413
+
414
+ # Make sure we're not deleting everything
415
+ assert person.jobs.count >= 2
416
+
417
+ assert_no_difference 'Job.count' do
418
+ assert_difference ['person.jobs.count', 'Reference.count'], -1 do
419
+ person.jobs_with_dependent_delete_all.delete(job)
420
+ end
421
+ end
422
+
423
+ # Check that the destroy callback on Reference did not run
424
+ assert_equal nil, person.reload.comments
425
+ ensure
426
+ Reference.make_comments = false
427
+ end
428
+
429
+ def test_delete_through_belongs_to_with_dependent_destroy
430
+ Reference.make_comments = true
431
+
432
+ person = people(:michael)
433
+ job = jobs(:magician)
434
+
435
+ # Make sure we're not deleting everything
436
+ assert person.jobs.count >= 2
437
+
438
+ assert_no_difference 'Job.count' do
439
+ assert_difference ['person.jobs.count', 'Reference.count'], -1 do
440
+ person.jobs_with_dependent_destroy.delete(job)
441
+ end
442
+ end
443
+
444
+ # Check that the destroy callback on Reference ran
445
+ assert_equal "Reference destroyed", person.reload.comments
446
+ ensure
447
+ Reference.make_comments = false
448
+ end
449
+
450
+ def test_belongs_to_with_dependent_destroy
451
+ person = PersonWithDependentDestroyJobs.find(1)
452
+
453
+ # Create a reference which is not linked to a job. This should not be destroyed.
454
+ person.references.create!
455
+
456
+ assert_no_difference 'Job.count' do
457
+ assert_difference 'Reference.count', -person.jobs.count do
458
+ person.destroy
459
+ end
460
+ end
461
+ end
462
+
463
+ def test_belongs_to_with_dependent_delete_all
464
+ person = PersonWithDependentDeleteAllJobs.find(1)
465
+
466
+ # Create a reference which is not linked to a job. This should not be destroyed.
467
+ person.references.create!
468
+
469
+ assert_no_difference 'Job.count' do
470
+ assert_difference 'Reference.count', -person.jobs.count do
471
+ person.destroy
472
+ end
473
+ end
474
+ end
475
+
476
+ def test_belongs_to_with_dependent_nullify
477
+ person = PersonWithDependentNullifyJobs.find(1)
478
+
479
+ references = person.references.to_a
480
+
481
+ assert_no_difference ['Reference.count', 'Job.count'] do
482
+ person.destroy
483
+ end
484
+
485
+ references.each do |reference|
486
+ assert_equal nil, reference.reload.job_id
487
+ end
488
+ end
489
+
490
+ def test_update_counter_caches_on_delete
491
+ post = posts(:welcome)
492
+ tag = post.tags.create!(:name => 'doomed')
493
+
494
+ assert_difference ['post.reload.tags_count'], -1 do
495
+ posts(:welcome).tags.delete(tag)
496
+ end
497
+ end
498
+
499
+ def test_update_counter_caches_on_delete_with_dependent_destroy
500
+ post = posts(:welcome)
501
+ tag = post.tags.create!(:name => 'doomed')
502
+ post.update_columns(tags_with_destroy_count: post.tags.count)
503
+
504
+ assert_difference ['post.reload.tags_with_destroy_count'], -1 do
505
+ posts(:welcome).tags_with_destroy.delete(tag)
506
+ end
507
+ end
508
+
509
+ def test_update_counter_caches_on_delete_with_dependent_nullify
510
+ post = posts(:welcome)
511
+ tag = post.tags.create!(:name => 'doomed')
512
+ post.update_columns(tags_with_nullify_count: post.tags.count)
513
+
514
+ assert_no_difference 'post.reload.tags_count' do
515
+ assert_difference 'post.reload.tags_with_nullify_count', -1 do
516
+ posts(:welcome).tags_with_nullify.delete(tag)
517
+ end
518
+ end
519
+ end
520
+
521
+ def test_update_counter_caches_on_replace_association
522
+ post = posts(:welcome)
523
+ tag = post.tags.create!(:name => 'doomed')
524
+ tag.tagged_posts << posts(:thinking)
525
+
526
+ tag.tagged_posts = []
527
+ post.reload
528
+
529
+ assert_equal(post.taggings.count, post.tags_count)
530
+ end
531
+
532
+ def test_update_counter_caches_on_destroy
533
+ post = posts(:welcome)
534
+ tag = post.tags.create!(name: 'doomed')
535
+
536
+ assert_difference 'post.reload.tags_count', -1 do
537
+ tag.tagged_posts.destroy(post)
538
+ end
539
+ end
540
+
541
+ def test_replace_association
542
+ assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)}
543
+
544
+ # 1 query to delete the existing reader (michael)
545
+ # 1 query to associate the new reader (david)
546
+ assert_queries(2) do
547
+ posts(:welcome).people = [people(:david)]
548
+ end
549
+
550
+ assert_queries(0){
551
+ assert posts(:welcome).people.include?(people(:david))
552
+ assert !posts(:welcome).people.include?(people(:michael))
553
+ }
554
+
555
+ assert posts(:welcome).reload.people(true).include?(people(:david))
556
+ assert !posts(:welcome).reload.people(true).include?(people(:michael))
557
+ end
558
+
559
+ def test_replace_order_is_preserved
560
+ posts(:welcome).people.clear
561
+ posts(:welcome).people = [people(:david), people(:michael)]
562
+ assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id)
563
+
564
+ # Test the inverse order in case the first success was a coincidence
565
+ posts(:welcome).people.clear
566
+ posts(:welcome).people = [people(:michael), people(:david)]
567
+ assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id)
568
+ end
569
+
570
+ def test_replace_by_id_order_is_preserved
571
+ posts(:welcome).people.clear
572
+ posts(:welcome).person_ids = [people(:david).id, people(:michael).id]
573
+ assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id)
574
+
575
+ # Test the inverse order in case the first success was a coincidence
576
+ posts(:welcome).people.clear
577
+ posts(:welcome).person_ids = [people(:michael).id, people(:david).id]
578
+ assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id)
579
+ end
580
+
581
+ def test_associate_with_create
582
+ assert_queries(1) { posts(:thinking) }
583
+
584
+ # 1 query for the new record, 1 for the join table record
585
+ # No need to update the actual collection yet!
586
+ assert_queries(2) do
587
+ posts(:thinking).people.create(:first_name=>"Jeb")
588
+ end
589
+
590
+ # *Now* we actually need the collection so it's loaded
591
+ assert_queries(1) do
592
+ assert posts(:thinking).people.collect(&:first_name).include?("Jeb")
593
+ end
594
+
595
+ assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Jeb")
596
+ end
597
+
598
+ def test_through_record_is_built_when_created_with_where
599
+ assert_difference("posts(:thinking).readers.count", 1) do
600
+ posts(:thinking).people.where(first_name: "Jeb").create
601
+ end
602
+ end
603
+
604
+ def test_associate_with_create_and_no_options
605
+ peeps = posts(:thinking).people.count
606
+ posts(:thinking).people.create(:first_name => 'foo')
607
+ assert_equal peeps + 1, posts(:thinking).people.count
608
+ end
609
+
610
+ def test_associate_with_create_with_through_having_conditions
611
+ impatient_people = posts(:thinking).impatient_people.count
612
+ posts(:thinking).impatient_people.create!(:first_name => 'foo')
613
+ assert_equal impatient_people + 1, posts(:thinking).impatient_people.count
614
+ end
615
+
616
+ def test_associate_with_create_exclamation_and_no_options
617
+ peeps = posts(:thinking).people.count
618
+ posts(:thinking).people.create!(:first_name => 'foo')
619
+ assert_equal peeps + 1, posts(:thinking).people.count
620
+ end
621
+
622
+ def test_create_on_new_record
623
+ p = Post.new
624
+
625
+ error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create(:first_name => "mew") }
626
+ assert_equal "You cannot call create unless the parent is saved", error.message
627
+
628
+ error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create!(:first_name => "snow") }
629
+ assert_equal "You cannot call create unless the parent is saved", error.message
630
+ end
631
+
632
+ def test_associate_with_create_and_invalid_options
633
+ firm = companies(:first_firm)
634
+ assert_no_difference('firm.developers.count') { assert_nothing_raised { firm.developers.create(:name => '0') } }
635
+ end
636
+
637
+ def test_associate_with_create_and_valid_options
638
+ firm = companies(:first_firm)
639
+ assert_difference('firm.developers.count', 1) { firm.developers.create(:name => 'developer') }
640
+ end
641
+
642
+ def test_associate_with_create_bang_and_invalid_options
643
+ firm = companies(:first_firm)
644
+ assert_no_difference('firm.developers.count') { assert_raises(ActiveRecord::RecordInvalid) { firm.developers.create!(:name => '0') } }
645
+ end
646
+
647
+ def test_associate_with_create_bang_and_valid_options
648
+ firm = companies(:first_firm)
649
+ assert_difference('firm.developers.count', 1) { firm.developers.create!(:name => 'developer') }
650
+ end
651
+
652
+ def test_push_with_invalid_record
653
+ firm = companies(:first_firm)
654
+ assert_raises(ActiveRecord::RecordInvalid) { firm.developers << Developer.new(:name => '0') }
655
+ end
656
+
657
+ def test_push_with_invalid_join_record
658
+ repair_validations(Contract) do
659
+ Contract.validate {|r| r.errors[:base] << 'Invalid Contract' }
660
+
661
+ firm = companies(:first_firm)
662
+ lifo = Developer.new(:name => 'lifo')
663
+ assert_raises(ActiveRecord::RecordInvalid) { firm.developers << lifo }
664
+
665
+ lifo = Developer.create!(:name => 'lifo')
666
+ assert_raises(ActiveRecord::RecordInvalid) { firm.developers << lifo }
667
+ end
668
+ end
669
+
670
+ def test_clear_associations
671
+ assert_queries(2) { posts(:welcome);posts(:welcome).people(true) }
672
+
673
+ assert_queries(1) do
674
+ posts(:welcome).people.clear
675
+ end
676
+
677
+ assert_queries(0) do
678
+ assert posts(:welcome).people.empty?
679
+ end
680
+
681
+ assert posts(:welcome).reload.people(true).empty?
682
+ end
683
+
684
+ def test_association_callback_ordering
685
+ Post.reset_log
686
+ log = Post.log
687
+ post = posts(:thinking)
688
+
689
+ post.people_with_callbacks << people(:michael)
690
+ assert_equal [
691
+ [:added, :before, "Michael"],
692
+ [:added, :after, "Michael"]
693
+ ], log.last(2)
694
+
695
+ post.people_with_callbacks.push(people(:david), Person.create!(:first_name => "Bob"), Person.new(:first_name => "Lary"))
696
+ assert_equal [
697
+ [:added, :before, "David"],
698
+ [:added, :after, "David"],
699
+ [:added, :before, "Bob"],
700
+ [:added, :after, "Bob"],
701
+ [:added, :before, "Lary"],
702
+ [:added, :after, "Lary"]
703
+ ],log.last(6)
704
+
705
+ post.people_with_callbacks.build(:first_name => "Ted")
706
+ assert_equal [
707
+ [:added, :before, "Ted"],
708
+ [:added, :after, "Ted"]
709
+ ], log.last(2)
710
+
711
+ post.people_with_callbacks.create(:first_name => "Sam")
712
+ assert_equal [
713
+ [:added, :before, "Sam"],
714
+ [:added, :after, "Sam"]
715
+ ], log.last(2)
716
+
717
+ post.people_with_callbacks = [people(:michael),people(:david), Person.new(:first_name => "Julian"), Person.create!(:first_name => "Roger")]
718
+ assert_equal((%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort)
719
+ assert_equal [
720
+ [:added, :before, "Julian"],
721
+ [:added, :after, "Julian"],
722
+ [:added, :before, "Roger"],
723
+ [:added, :after, "Roger"]
724
+ ], log.last(4)
725
+ end
726
+
727
+ def test_dynamic_find_should_respect_association_include
728
+ # SQL error in sort clause if :include is not included
729
+ # due to Unknown column 'comments.id'
730
+ assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title('Welcome to the weblog')
731
+ end
732
+
733
+ def test_count_with_include_should_alias_join_table
734
+ assert_equal 2, people(:michael).posts.includes(:readers).count
735
+ end
736
+
737
+ def test_inner_join_with_quoted_table_name
738
+ assert_equal 2, people(:michael).jobs.size
739
+ end
740
+
741
+ def test_get_ids
742
+ assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort
743
+ end
744
+
745
+ def test_get_ids_for_has_many_through_with_conditions_should_not_preload
746
+ Tagging.create!(:taggable_type => 'Post', :taggable_id => posts(:welcome).id, :tag => tags(:misc))
747
+ ActiveRecord::Associations::Preloader.expects(:new).never
748
+ posts(:welcome).misc_tag_ids
749
+ end
750
+
751
+ def test_get_ids_for_loaded_associations
752
+ person = people(:michael)
753
+ person.posts(true)
754
+ assert_queries(0) do
755
+ person.post_ids
756
+ person.post_ids
757
+ end
758
+ end
759
+
760
+ def test_get_ids_for_unloaded_associations_does_not_load_them
761
+ person = people(:michael)
762
+ assert !person.posts.loaded?
763
+ assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort
764
+ assert !person.posts.loaded?
765
+ end
766
+
767
+ def test_association_proxy_transaction_method_starts_transaction_in_association_class
768
+ Tag.expects(:transaction)
769
+ Post.first.tags.transaction do
770
+ # nothing
771
+ end
772
+ end
773
+
774
+ def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist
775
+ post = Post.create!(:title => "TITLE", :body => "BODY")
776
+ assert_equal [], post.author_favorites
777
+ end
778
+
779
+ def test_has_many_association_through_a_belongs_to_association
780
+ author = authors(:mary)
781
+ post = Post.create!(:author => author, :title => "TITLE", :body => "BODY")
782
+ author.author_favorites.create(:favorite_author_id => 1)
783
+ author.author_favorites.create(:favorite_author_id => 2)
784
+ author.author_favorites.create(:favorite_author_id => 3)
785
+ assert_equal post.author.author_favorites, post.author_favorites
786
+ end
787
+
788
+ def test_merge_join_association_with_has_many_through_association_proxy
789
+ author = authors(:mary)
790
+ assert_nothing_raised { author.comments.ratings.to_sql }
791
+ end
792
+
793
+ def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
794
+ assert_equal 2, owners(:blackbeard).toys.count
795
+ end
796
+
797
+ def test_find_on_has_many_association_collection_with_include_and_conditions
798
+ post_with_no_comments = people(:michael).posts_with_no_comments.first
799
+ assert_equal post_with_no_comments, posts(:authorless)
800
+ end
801
+
802
+ def test_has_many_through_has_one_reflection
803
+ assert_equal [comments(:eager_sti_on_associations_vs_comment)], authors(:david).very_special_comments
804
+ end
805
+
806
+ def test_modifying_has_many_through_has_one_reflection_should_raise
807
+ [
808
+ lambda { authors(:david).very_special_comments = [VerySpecialComment.create!(:body => "Gorp!", :post_id => 1011), VerySpecialComment.create!(:body => "Eep!", :post_id => 1012)] },
809
+ lambda { authors(:david).very_special_comments << VerySpecialComment.create!(:body => "Hoohah!", :post_id => 1013) },
810
+ lambda { authors(:david).very_special_comments.delete(authors(:david).very_special_comments.first) },
811
+ ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
812
+ end
813
+
814
+ def test_has_many_association_through_a_has_many_association_to_self
815
+ sarah = Person.create!(:first_name => 'Sarah', :primary_contact_id => people(:susan).id, :gender => 'F', :number1_fan_id => 1)
816
+ john = Person.create!(:first_name => 'John', :primary_contact_id => sarah.id, :gender => 'M', :number1_fan_id => 1)
817
+ assert_equal sarah.agents, [john]
818
+ assert_equal people(:susan).agents.flat_map(&:agents), people(:susan).agents_of_agents
819
+ end
820
+
821
+ def test_associate_existing_with_nonstandard_primary_key_on_belongs_to
822
+ Categorization.create(:author => authors(:mary), :named_category_name => categories(:general).name)
823
+ assert_equal categories(:general), authors(:mary).named_categories.first
824
+ end
825
+
826
+ def test_collection_build_with_nonstandard_primary_key_on_belongs_to
827
+ author = authors(:mary)
828
+ category = author.named_categories.build(:name => "Primary")
829
+ author.save
830
+ assert Categorization.exists?(:author_id => author.id, :named_category_name => category.name)
831
+ assert author.named_categories(true).include?(category)
832
+ end
833
+
834
+ def test_collection_create_with_nonstandard_primary_key_on_belongs_to
835
+ author = authors(:mary)
836
+ category = author.named_categories.create(:name => "Primary")
837
+ assert Categorization.exists?(:author_id => author.id, :named_category_name => category.name)
838
+ assert author.named_categories(true).include?(category)
839
+ end
840
+
841
+ def test_collection_exists
842
+ author = authors(:mary)
843
+ category = Category.create!(author_ids: [author.id], name: "Primary")
844
+ assert category.authors.exists?(id: author.id)
845
+ assert category.reload.authors.exists?(id: author.id)
846
+ end
847
+
848
+ def test_collection_delete_with_nonstandard_primary_key_on_belongs_to
849
+ author = authors(:mary)
850
+ category = author.named_categories.create(:name => "Primary")
851
+ author.named_categories.delete(category)
852
+ assert !Categorization.exists?(:author_id => author.id, :named_category_name => category.name)
853
+ assert author.named_categories(true).empty?
854
+ end
855
+
856
+ def test_collection_singular_ids_getter_with_string_primary_keys
857
+ book = books(:awdr)
858
+ assert_equal 2, book.subscriber_ids.size
859
+ assert_equal [subscribers(:first).nick, subscribers(:second).nick].sort, book.subscriber_ids.sort
860
+ end
861
+
862
+ def test_collection_singular_ids_setter
863
+ company = companies(:rails_core)
864
+ dev = Developer.first
865
+
866
+ company.developer_ids = [dev.id]
867
+ assert_equal [dev], company.developers
868
+ end
869
+
870
+ def test_collection_singular_ids_setter_with_string_primary_keys
871
+ assert_nothing_raised do
872
+ book = books(:awdr)
873
+ book.subscriber_ids = [subscribers(:second).nick]
874
+ assert_equal [subscribers(:second)], book.subscribers(true)
875
+
876
+ book.subscriber_ids = []
877
+ assert_equal [], book.subscribers(true)
878
+ end
879
+
880
+ end
881
+
882
+ def test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set
883
+ company = companies(:rails_core)
884
+ ids = [Developer.first.id, -9999]
885
+ assert_raises(ActiveRecord::RecordNotFound) {company.developer_ids= ids}
886
+ end
887
+
888
+ def test_build_a_model_from_hm_through_association_with_where_clause
889
+ assert_nothing_raised { books(:awdr).subscribers.where(:nick => "marklazz").build }
890
+ end
891
+
892
+ def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_where_clause
893
+ new_subscriber = books(:awdr).subscribers.where(:nick => "marklazz").build
894
+ assert_equal new_subscriber.nick, "marklazz"
895
+ end
896
+
897
+ def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_multiple_where_clauses
898
+ new_subscriber = books(:awdr).subscribers.where(:nick => "marklazz").where(:name => 'Marcelo Giorgi').build
899
+ assert_equal new_subscriber.nick, "marklazz"
900
+ assert_equal new_subscriber.name, "Marcelo Giorgi"
901
+ end
902
+
903
+ def test_include_method_in_association_through_should_return_true_for_instance_added_with_build
904
+ person = Person.new
905
+ reference = person.references.build
906
+ job = reference.build_job
907
+ assert person.jobs.include?(job)
908
+ end
909
+
910
+ def test_include_method_in_association_through_should_return_true_for_instance_added_with_nested_builds
911
+ author = Author.new
912
+ post = author.posts.build
913
+ comment = post.comments.build
914
+ assert author.comments.include?(comment)
915
+ end
916
+
917
+ def test_through_association_readonly_should_be_false
918
+ assert !people(:michael).posts.first.readonly?
919
+ assert !people(:michael).posts.to_a.first.readonly?
920
+ end
921
+
922
+ def test_can_update_through_association
923
+ assert_nothing_raised do
924
+ people(:michael).posts.first.update!(title: "Can write")
925
+ end
926
+ end
927
+
928
+ def test_has_many_through_polymorphic_with_primary_key_option
929
+ assert_equal [categories(:general)], authors(:david).essay_categories
930
+
931
+ authors = Author.joins(:essay_categories).where('categories.id' => categories(:general).id)
932
+ assert_equal authors(:david), authors.first
933
+
934
+ assert_equal [owners(:blackbeard)], authors(:david).essay_owners
935
+
936
+ authors = Author.joins(:essay_owners).where("owners.name = 'blackbeard'")
937
+ assert_equal authors(:david), authors.first
938
+ end
939
+
940
+ def test_has_many_through_with_primary_key_option
941
+ assert_equal [categories(:general)], authors(:david).essay_categories_2
942
+
943
+ authors = Author.joins(:essay_categories_2).where('categories.id' => categories(:general).id)
944
+ assert_equal authors(:david), authors.first
945
+ end
946
+
947
+ def test_size_of_through_association_should_increase_correctly_when_has_many_association_is_added
948
+ post = posts(:thinking)
949
+ readers = post.readers.size
950
+ post.people << people(:michael)
951
+ assert_equal readers + 1, post.readers.size
952
+ end
953
+
954
+ def test_has_many_through_with_default_scope_on_join_model
955
+ assert_equal posts(:welcome).comments.order('id').to_a, authors(:david).comments_on_first_posts
956
+ end
957
+
958
+ def test_create_has_many_through_with_default_scope_on_join_model
959
+ category = authors(:david).special_categories.create(:name => "Foo")
960
+ assert_equal 1, category.categorizations.where(:special => true).count
961
+ end
962
+
963
+ def test_joining_has_many_through_with_uniq
964
+ mary = Author.joins(:unique_categorized_posts).where(:id => authors(:mary).id).first
965
+ assert_equal 1, mary.unique_categorized_posts.length
966
+ assert_equal 1, mary.unique_categorized_post_ids.length
967
+ end
968
+
969
+ def test_joining_has_many_through_belongs_to
970
+ posts = Post.joins(:author_categorizations).order('posts.id').
971
+ where('categorizations.id' => categorizations(:mary_thinking_sti).id)
972
+
973
+ assert_equal [posts(:eager_other), posts(:misc_by_mary), posts(:other_by_mary)], posts
974
+ end
975
+
976
+ def test_select_chosen_fields_only
977
+ author = authors(:david)
978
+ assert_equal ['body', 'id'].sort, author.comments.select('comments.body').first.attributes.keys.sort
979
+ end
980
+
981
+ def test_get_has_many_through_belongs_to_ids_with_conditions
982
+ assert_equal [categories(:general).id], authors(:mary).categories_like_general_ids
983
+ end
984
+
985
+ def test_get_collection_singular_ids_on_has_many_through_with_conditions_and_include
986
+ person = Person.first
987
+ assert_equal person.posts_with_no_comment_ids, person.posts_with_no_comments.map(&:id)
988
+ end
989
+
990
+ def test_count_has_many_through_with_named_scope
991
+ assert_equal 2, authors(:mary).categories.count
992
+ assert_equal 1, authors(:mary).categories.general.count
993
+ end
994
+
995
+ def test_has_many_through_belongs_to_should_update_when_the_through_foreign_key_changes
996
+ post = posts(:eager_other)
997
+
998
+ post.author_categorizations
999
+ proxy = post.send(:association_instance_get, :author_categorizations)
1000
+
1001
+ assert !proxy.stale_target?
1002
+ assert_equal authors(:mary).categorizations.sort_by(&:id), post.author_categorizations.sort_by(&:id)
1003
+
1004
+ post.author_id = authors(:david).id
1005
+
1006
+ assert proxy.stale_target?
1007
+ assert_equal authors(:david).categorizations.sort_by(&:id), post.author_categorizations.sort_by(&:id)
1008
+ end
1009
+
1010
+ def test_create_with_conditions_hash_on_through_association
1011
+ member = members(:groucho)
1012
+ club = member.clubs.create!
1013
+
1014
+ assert_equal true, club.reload.membership.favourite
1015
+ end
1016
+
1017
+ def test_deleting_from_has_many_through_a_belongs_to_should_not_try_to_update_counter
1018
+ post = posts(:welcome)
1019
+ address = author_addresses(:david_address)
1020
+
1021
+ assert post.author_addresses.include?(address)
1022
+ post.author_addresses.delete(address)
1023
+ assert post[:author_count].nil?
1024
+ end
1025
+
1026
+ def test_primary_key_option_on_source
1027
+ post = posts(:welcome)
1028
+ category = categories(:general)
1029
+ Categorization.create!(:post_id => post.id, :named_category_name => category.name)
1030
+
1031
+ assert_equal [category], post.named_categories
1032
+ assert_equal [category.name], post.named_category_ids # checks when target loaded
1033
+ assert_equal [category.name], post.reload.named_category_ids # checks when target no loaded
1034
+ end
1035
+
1036
+ def test_create_should_not_raise_exception_when_join_record_has_errors
1037
+ repair_validations(Categorization) do
1038
+ Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
1039
+ Category.create(:name => 'Fishing', :authors => [Author.first])
1040
+ end
1041
+ end
1042
+
1043
+ def test_save_should_not_raise_exception_when_join_record_has_errors
1044
+ repair_validations(Categorization) do
1045
+ Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
1046
+ c = Category.create(:name => 'Fishing', :authors => [Author.first])
1047
+ c.save
1048
+ end
1049
+ end
1050
+
1051
+ def test_assign_array_to_new_record_builds_join_records
1052
+ c = Category.new(:name => 'Fishing', :authors => [Author.first])
1053
+ assert_equal 1, c.categorizations.size
1054
+ end
1055
+
1056
+ def test_create_bang_should_raise_exception_when_join_record_has_errors
1057
+ repair_validations(Categorization) do
1058
+ Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
1059
+ assert_raises(ActiveRecord::RecordInvalid) do
1060
+ Category.create!(:name => 'Fishing', :authors => [Author.first])
1061
+ end
1062
+ end
1063
+ end
1064
+
1065
+ def test_save_bang_should_raise_exception_when_join_record_has_errors
1066
+ repair_validations(Categorization) do
1067
+ Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
1068
+ c = Category.new(:name => 'Fishing', :authors => [Author.first])
1069
+ assert_raises(ActiveRecord::RecordInvalid) do
1070
+ c.save!
1071
+ end
1072
+ end
1073
+ end
1074
+
1075
+ def test_create_bang_returns_falsy_when_join_record_has_errors
1076
+ repair_validations(Categorization) do
1077
+ Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' }
1078
+ c = Category.new(:name => 'Fishing', :authors => [Author.first])
1079
+ assert !c.save
1080
+ end
1081
+ end
1082
+
1083
+ def test_preloading_empty_through_association_via_joins
1084
+ person = Person.create!(:first_name => "Gaga")
1085
+ person = Person.where(:id => person.id).where('readers.id = 1 or 1=1').references(:readers).includes(:posts).to_a.first
1086
+
1087
+ assert person.posts.loaded?, 'person.posts should be loaded'
1088
+ assert_equal [], person.posts
1089
+ end
1090
+
1091
+ def test_explicitly_joining_join_table
1092
+ assert_equal owners(:blackbeard).toys, owners(:blackbeard).toys.with_pet
1093
+ end
1094
+
1095
+ def test_has_many_through_with_polymorphic_source
1096
+ post = tags(:general).tagged_posts.create! :title => "foo", :body => "bar"
1097
+ assert_equal [tags(:general)], post.reload.tags
1098
+ end
1099
+
1100
+ def test_has_many_through_obeys_order_on_through_association
1101
+ owner = owners(:blackbeard)
1102
+ assert owner.toys.to_sql.include?("pets.name desc")
1103
+ assert_equal ["parrot", "bulbul"], owner.toys.map { |r| r.pet.name }
1104
+ end
1105
+
1106
+ def test_has_many_through_associations_on_new_records_use_null_relations
1107
+ person = Person.new
1108
+
1109
+ assert_no_queries(ignore_none: false) do
1110
+ assert_equal [], person.posts
1111
+ assert_equal [], person.posts.where(body: 'omg')
1112
+ assert_equal [], person.posts.pluck(:body)
1113
+ assert_equal 0, person.posts.sum(:tags_count)
1114
+ assert_equal 0, person.posts.count
1115
+ end
1116
+ end
1117
+
1118
+ def test_has_many_through_with_default_scope_on_the_target
1119
+ person = people(:michael)
1120
+ assert_equal [posts(:thinking)], person.first_posts
1121
+
1122
+ readers(:michael_authorless).update(first_post_id: 1)
1123
+ assert_equal [posts(:thinking)], person.reload.first_posts
1124
+ end
1125
+
1126
+ def test_has_many_through_with_includes_in_through_association_scope
1127
+ assert_not_empty posts(:welcome).author_address_extra_with_address
1128
+ end
1129
+
1130
+ def test_insert_records_via_has_many_through_association_with_scope
1131
+ club = Club.create!
1132
+ member = Member.create!
1133
+ Membership.create!(club: club, member: member)
1134
+
1135
+ club.favourites << member
1136
+ assert_equal [member], club.favourites
1137
+
1138
+ club.reload
1139
+ assert_equal [member], club.favourites
1140
+ end
1141
+
1142
+ def test_has_many_through_unscope_default_scope
1143
+ post = Post.create!(:title => 'Beaches', :body => "I like beaches!")
1144
+ Reader.create! :person => people(:david), :post => post
1145
+ LazyReader.create! :person => people(:susan), :post => post
1146
+
1147
+ assert_equal 2, post.people.to_a.size
1148
+ assert_equal 1, post.lazy_people.to_a.size
1149
+
1150
+ assert_equal 2, post.lazy_readers_unscope_skimmers.to_a.size
1151
+ assert_equal 2, post.lazy_people_unscope_skimmers.to_a.size
1152
+ end
1153
+
1154
+ def test_has_many_through_add_with_sti_middle_relation
1155
+ club = SuperClub.create!(name: 'Fight Club')
1156
+ member = Member.create!(name: 'Tyler Durden')
1157
+
1158
+ club.members << member
1159
+ assert_equal 1, SuperMembership.where(member_id: member.id, club_id: club.id).count
1160
+ end
1161
+
1162
+ def test_build_for_has_many_through_association
1163
+ organization = organizations(:nsa)
1164
+ author = organization.author
1165
+ post_direct = author.posts.build
1166
+ post_through = organization.posts.build
1167
+ assert_equal post_direct.author_id, post_through.author_id
1168
+ end
1169
+
1170
+ def test_has_many_through_with_scope_that_should_not_be_fully_merged
1171
+ Club.has_many :distinct_memberships, -> { distinct }, class_name: "Membership"
1172
+ Club.has_many :special_favourites, through: :distinct_memberships, source: :member
1173
+
1174
+ assert_nil Club.new.special_favourites.distinct_value
1175
+ end
1176
+
1177
+ def test_has_many_through_do_not_cache_association_reader_if_the_though_method_has_default_scopes
1178
+ member = Member.create!
1179
+ club = Club.create!
1180
+ TenantMembership.create!(
1181
+ member: member,
1182
+ club: club
1183
+ )
1184
+
1185
+ TenantMembership.current_member = member
1186
+
1187
+ tenant_clubs = member.tenant_clubs
1188
+ assert_equal [club], tenant_clubs
1189
+
1190
+ TenantMembership.current_member = nil
1191
+
1192
+ other_member = Member.create!
1193
+ other_club = Club.create!
1194
+ TenantMembership.create!(
1195
+ member: other_member,
1196
+ club: other_club
1197
+ )
1198
+
1199
+ tenant_clubs = other_member.tenant_clubs
1200
+ assert_equal [other_club], tenant_clubs
1201
+ ensure
1202
+ TenantMembership.current_member = nil
1203
+ end
1204
+ end