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