activerecord_csi 2.3.5.p6

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 (333) hide show
  1. data/CHANGELOG +5858 -0
  2. data/README +351 -0
  3. data/RUNNING_UNIT_TESTS +36 -0
  4. data/Rakefile +270 -0
  5. data/examples/associations.png +0 -0
  6. data/examples/performance.rb +162 -0
  7. data/install.rb +30 -0
  8. data/lib/active_record/aggregations.rb +261 -0
  9. data/lib/active_record/association_preload.rb +389 -0
  10. data/lib/active_record/associations/association_collection.rb +475 -0
  11. data/lib/active_record/associations/association_proxy.rb +278 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +76 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +53 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
  15. data/lib/active_record/associations/has_many_association.rb +122 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +266 -0
  17. data/lib/active_record/associations/has_one_association.rb +133 -0
  18. data/lib/active_record/associations/has_one_through_association.rb +37 -0
  19. data/lib/active_record/associations.rb +2241 -0
  20. data/lib/active_record/attribute_methods.rb +388 -0
  21. data/lib/active_record/autosave_association.rb +364 -0
  22. data/lib/active_record/base.rb +3171 -0
  23. data/lib/active_record/batches.rb +81 -0
  24. data/lib/active_record/calculations.rb +311 -0
  25. data/lib/active_record/callbacks.rb +360 -0
  26. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +371 -0
  27. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +139 -0
  28. data/lib/active_record/connection_adapters/abstract/database_statements.rb +289 -0
  29. data/lib/active_record/connection_adapters/abstract/query_cache.rb +94 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +722 -0
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +434 -0
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +241 -0
  34. data/lib/active_record/connection_adapters/mysql_adapter.rb +630 -0
  35. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1113 -0
  36. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  37. data/lib/active_record/connection_adapters/sqlite_adapter.rb +453 -0
  38. data/lib/active_record/dirty.rb +183 -0
  39. data/lib/active_record/dynamic_finder_match.rb +41 -0
  40. data/lib/active_record/dynamic_scope_match.rb +25 -0
  41. data/lib/active_record/fixtures.rb +996 -0
  42. data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
  43. data/lib/active_record/locale/en.yml +58 -0
  44. data/lib/active_record/locking/optimistic.rb +148 -0
  45. data/lib/active_record/locking/pessimistic.rb +55 -0
  46. data/lib/active_record/migration.rb +566 -0
  47. data/lib/active_record/named_scope.rb +192 -0
  48. data/lib/active_record/nested_attributes.rb +392 -0
  49. data/lib/active_record/observer.rb +197 -0
  50. data/lib/active_record/query_cache.rb +33 -0
  51. data/lib/active_record/reflection.rb +320 -0
  52. data/lib/active_record/schema.rb +51 -0
  53. data/lib/active_record/schema_dumper.rb +182 -0
  54. data/lib/active_record/serialization.rb +101 -0
  55. data/lib/active_record/serializers/json_serializer.rb +91 -0
  56. data/lib/active_record/serializers/xml_serializer.rb +357 -0
  57. data/lib/active_record/session_store.rb +326 -0
  58. data/lib/active_record/test_case.rb +66 -0
  59. data/lib/active_record/timestamp.rb +71 -0
  60. data/lib/active_record/transactions.rb +235 -0
  61. data/lib/active_record/validations.rb +1135 -0
  62. data/lib/active_record/version.rb +9 -0
  63. data/lib/active_record.rb +84 -0
  64. data/lib/activerecord.rb +2 -0
  65. data/test/assets/example.log +1 -0
  66. data/test/assets/flowers.jpg +0 -0
  67. data/test/cases/aaa_create_tables_test.rb +24 -0
  68. data/test/cases/active_schema_test_mysql.rb +100 -0
  69. data/test/cases/active_schema_test_postgresql.rb +24 -0
  70. data/test/cases/adapter_test.rb +145 -0
  71. data/test/cases/aggregations_test.rb +167 -0
  72. data/test/cases/ar_schema_test.rb +32 -0
  73. data/test/cases/associations/belongs_to_associations_test.rb +425 -0
  74. data/test/cases/associations/callbacks_test.rb +161 -0
  75. data/test/cases/associations/cascaded_eager_loading_test.rb +131 -0
  76. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
  77. data/test/cases/associations/eager_load_nested_include_test.rb +130 -0
  78. data/test/cases/associations/eager_singularization_test.rb +145 -0
  79. data/test/cases/associations/eager_test.rb +834 -0
  80. data/test/cases/associations/extension_test.rb +62 -0
  81. data/test/cases/associations/habtm_join_table_test.rb +56 -0
  82. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +822 -0
  83. data/test/cases/associations/has_many_associations_test.rb +1134 -0
  84. data/test/cases/associations/has_many_through_associations_test.rb +346 -0
  85. data/test/cases/associations/has_one_associations_test.rb +330 -0
  86. data/test/cases/associations/has_one_through_associations_test.rb +209 -0
  87. data/test/cases/associations/inner_join_association_test.rb +93 -0
  88. data/test/cases/associations/join_model_test.rb +712 -0
  89. data/test/cases/associations_test.rb +262 -0
  90. data/test/cases/attribute_methods_test.rb +305 -0
  91. data/test/cases/autosave_association_test.rb +1142 -0
  92. data/test/cases/base_test.rb +2154 -0
  93. data/test/cases/batches_test.rb +61 -0
  94. data/test/cases/binary_test.rb +30 -0
  95. data/test/cases/calculations_test.rb +348 -0
  96. data/test/cases/callbacks_observers_test.rb +38 -0
  97. data/test/cases/callbacks_test.rb +438 -0
  98. data/test/cases/class_inheritable_attributes_test.rb +32 -0
  99. data/test/cases/column_alias_test.rb +17 -0
  100. data/test/cases/column_definition_test.rb +70 -0
  101. data/test/cases/connection_pool_test.rb +25 -0
  102. data/test/cases/connection_test_firebird.rb +8 -0
  103. data/test/cases/connection_test_mysql.rb +64 -0
  104. data/test/cases/copy_table_test_sqlite.rb +80 -0
  105. data/test/cases/database_statements_test.rb +12 -0
  106. data/test/cases/datatype_test_postgresql.rb +204 -0
  107. data/test/cases/date_time_test.rb +37 -0
  108. data/test/cases/default_test_firebird.rb +16 -0
  109. data/test/cases/defaults_test.rb +111 -0
  110. data/test/cases/deprecated_finder_test.rb +30 -0
  111. data/test/cases/dirty_test.rb +316 -0
  112. data/test/cases/finder_respond_to_test.rb +76 -0
  113. data/test/cases/finder_test.rb +1066 -0
  114. data/test/cases/fixtures_test.rb +656 -0
  115. data/test/cases/helper.rb +68 -0
  116. data/test/cases/i18n_test.rb +46 -0
  117. data/test/cases/inheritance_test.rb +262 -0
  118. data/test/cases/invalid_date_test.rb +24 -0
  119. data/test/cases/json_serialization_test.rb +205 -0
  120. data/test/cases/lifecycle_test.rb +193 -0
  121. data/test/cases/locking_test.rb +304 -0
  122. data/test/cases/method_scoping_test.rb +704 -0
  123. data/test/cases/migration_test.rb +1523 -0
  124. data/test/cases/migration_test_firebird.rb +124 -0
  125. data/test/cases/mixin_test.rb +96 -0
  126. data/test/cases/modules_test.rb +81 -0
  127. data/test/cases/multiple_db_test.rb +85 -0
  128. data/test/cases/named_scope_test.rb +361 -0
  129. data/test/cases/nested_attributes_test.rb +581 -0
  130. data/test/cases/pk_test.rb +119 -0
  131. data/test/cases/pooled_connections_test.rb +103 -0
  132. data/test/cases/query_cache_test.rb +123 -0
  133. data/test/cases/readonly_test.rb +107 -0
  134. data/test/cases/reflection_test.rb +194 -0
  135. data/test/cases/reload_models_test.rb +22 -0
  136. data/test/cases/repair_helper.rb +50 -0
  137. data/test/cases/reserved_word_test_mysql.rb +176 -0
  138. data/test/cases/sanitize_test.rb +25 -0
  139. data/test/cases/schema_authorization_test_postgresql.rb +75 -0
  140. data/test/cases/schema_dumper_test.rb +211 -0
  141. data/test/cases/schema_test_postgresql.rb +178 -0
  142. data/test/cases/serialization_test.rb +47 -0
  143. data/test/cases/synonym_test_oracle.rb +17 -0
  144. data/test/cases/timestamp_test.rb +75 -0
  145. data/test/cases/transactions_test.rb +522 -0
  146. data/test/cases/unconnected_test.rb +32 -0
  147. data/test/cases/validations_i18n_test.rb +955 -0
  148. data/test/cases/validations_test.rb +1640 -0
  149. data/test/cases/xml_serialization_test.rb +240 -0
  150. data/test/config.rb +5 -0
  151. data/test/connections/jdbc_jdbcderby/connection.rb +18 -0
  152. data/test/connections/jdbc_jdbch2/connection.rb +18 -0
  153. data/test/connections/jdbc_jdbchsqldb/connection.rb +18 -0
  154. data/test/connections/jdbc_jdbcmysql/connection.rb +26 -0
  155. data/test/connections/jdbc_jdbcpostgresql/connection.rb +26 -0
  156. data/test/connections/jdbc_jdbcsqlite3/connection.rb +25 -0
  157. data/test/connections/native_db2/connection.rb +25 -0
  158. data/test/connections/native_firebird/connection.rb +26 -0
  159. data/test/connections/native_frontbase/connection.rb +27 -0
  160. data/test/connections/native_mysql/connection.rb +25 -0
  161. data/test/connections/native_openbase/connection.rb +21 -0
  162. data/test/connections/native_oracle/connection.rb +27 -0
  163. data/test/connections/native_postgresql/connection.rb +25 -0
  164. data/test/connections/native_sqlite/connection.rb +25 -0
  165. data/test/connections/native_sqlite3/connection.rb +25 -0
  166. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  167. data/test/connections/native_sybase/connection.rb +23 -0
  168. data/test/fixtures/accounts.yml +29 -0
  169. data/test/fixtures/all/developers.yml +0 -0
  170. data/test/fixtures/all/people.csv +0 -0
  171. data/test/fixtures/all/tasks.yml +0 -0
  172. data/test/fixtures/author_addresses.yml +5 -0
  173. data/test/fixtures/author_favorites.yml +4 -0
  174. data/test/fixtures/authors.yml +9 -0
  175. data/test/fixtures/binaries.yml +132 -0
  176. data/test/fixtures/books.yml +7 -0
  177. data/test/fixtures/categories/special_categories.yml +9 -0
  178. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  179. data/test/fixtures/categories.yml +14 -0
  180. data/test/fixtures/categories_ordered.yml +7 -0
  181. data/test/fixtures/categories_posts.yml +23 -0
  182. data/test/fixtures/categorizations.yml +17 -0
  183. data/test/fixtures/clubs.yml +6 -0
  184. data/test/fixtures/comments.yml +59 -0
  185. data/test/fixtures/companies.yml +56 -0
  186. data/test/fixtures/computers.yml +4 -0
  187. data/test/fixtures/courses.yml +7 -0
  188. data/test/fixtures/customers.yml +26 -0
  189. data/test/fixtures/developers.yml +21 -0
  190. data/test/fixtures/developers_projects.yml +17 -0
  191. data/test/fixtures/edges.yml +6 -0
  192. data/test/fixtures/entrants.yml +14 -0
  193. data/test/fixtures/fixture_database.sqlite3 +0 -0
  194. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  195. data/test/fixtures/fk_test_has_fk.yml +3 -0
  196. data/test/fixtures/fk_test_has_pk.yml +2 -0
  197. data/test/fixtures/funny_jokes.yml +10 -0
  198. data/test/fixtures/items.yml +4 -0
  199. data/test/fixtures/jobs.yml +7 -0
  200. data/test/fixtures/legacy_things.yml +3 -0
  201. data/test/fixtures/mateys.yml +4 -0
  202. data/test/fixtures/member_types.yml +6 -0
  203. data/test/fixtures/members.yml +6 -0
  204. data/test/fixtures/memberships.yml +20 -0
  205. data/test/fixtures/minimalistics.yml +2 -0
  206. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  207. data/test/fixtures/mixins.yml +29 -0
  208. data/test/fixtures/movies.yml +7 -0
  209. data/test/fixtures/naked/csv/accounts.csv +1 -0
  210. data/test/fixtures/naked/yml/accounts.yml +1 -0
  211. data/test/fixtures/naked/yml/companies.yml +1 -0
  212. data/test/fixtures/naked/yml/courses.yml +1 -0
  213. data/test/fixtures/organizations.yml +5 -0
  214. data/test/fixtures/owners.yml +7 -0
  215. data/test/fixtures/parrots.yml +27 -0
  216. data/test/fixtures/parrots_pirates.yml +7 -0
  217. data/test/fixtures/people.yml +15 -0
  218. data/test/fixtures/pets.yml +14 -0
  219. data/test/fixtures/pirates.yml +9 -0
  220. data/test/fixtures/posts.yml +52 -0
  221. data/test/fixtures/price_estimates.yml +7 -0
  222. data/test/fixtures/projects.yml +7 -0
  223. data/test/fixtures/readers.yml +9 -0
  224. data/test/fixtures/references.yml +17 -0
  225. data/test/fixtures/reserved_words/distinct.yml +5 -0
  226. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  227. data/test/fixtures/reserved_words/group.yml +14 -0
  228. data/test/fixtures/reserved_words/select.yml +8 -0
  229. data/test/fixtures/reserved_words/values.yml +7 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/sponsors.yml +9 -0
  232. data/test/fixtures/subscribers.yml +7 -0
  233. data/test/fixtures/subscriptions.yml +12 -0
  234. data/test/fixtures/taggings.yml +28 -0
  235. data/test/fixtures/tags.yml +7 -0
  236. data/test/fixtures/tasks.yml +7 -0
  237. data/test/fixtures/topics.yml +42 -0
  238. data/test/fixtures/toys.yml +4 -0
  239. data/test/fixtures/treasures.yml +10 -0
  240. data/test/fixtures/vertices.yml +4 -0
  241. data/test/fixtures/warehouse-things.yml +3 -0
  242. data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
  243. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
  244. data/test/migrations/duplicate/1_people_have_last_names.rb +9 -0
  245. data/test/migrations/duplicate/2_we_need_reminders.rb +12 -0
  246. data/test/migrations/duplicate/3_foo.rb +7 -0
  247. data/test/migrations/duplicate/3_innocent_jointable.rb +12 -0
  248. data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
  249. data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
  250. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +12 -0
  251. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +9 -0
  252. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +12 -0
  253. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +9 -0
  254. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
  255. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
  256. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
  257. data/test/migrations/missing/1_people_have_last_names.rb +9 -0
  258. data/test/migrations/missing/3_we_need_reminders.rb +12 -0
  259. data/test/migrations/missing/4_innocent_jointable.rb +12 -0
  260. data/test/migrations/valid/1_people_have_last_names.rb +9 -0
  261. data/test/migrations/valid/2_we_need_reminders.rb +12 -0
  262. data/test/migrations/valid/3_innocent_jointable.rb +12 -0
  263. data/test/models/author.rb +146 -0
  264. data/test/models/auto_id.rb +4 -0
  265. data/test/models/binary.rb +2 -0
  266. data/test/models/bird.rb +3 -0
  267. data/test/models/book.rb +4 -0
  268. data/test/models/categorization.rb +5 -0
  269. data/test/models/category.rb +34 -0
  270. data/test/models/citation.rb +6 -0
  271. data/test/models/club.rb +13 -0
  272. data/test/models/column_name.rb +3 -0
  273. data/test/models/comment.rb +29 -0
  274. data/test/models/company.rb +171 -0
  275. data/test/models/company_in_module.rb +61 -0
  276. data/test/models/computer.rb +3 -0
  277. data/test/models/contact.rb +16 -0
  278. data/test/models/contract.rb +5 -0
  279. data/test/models/course.rb +3 -0
  280. data/test/models/customer.rb +73 -0
  281. data/test/models/default.rb +2 -0
  282. data/test/models/developer.rb +101 -0
  283. data/test/models/edge.rb +5 -0
  284. data/test/models/entrant.rb +3 -0
  285. data/test/models/essay.rb +3 -0
  286. data/test/models/event.rb +3 -0
  287. data/test/models/guid.rb +2 -0
  288. data/test/models/item.rb +7 -0
  289. data/test/models/job.rb +5 -0
  290. data/test/models/joke.rb +3 -0
  291. data/test/models/keyboard.rb +3 -0
  292. data/test/models/legacy_thing.rb +3 -0
  293. data/test/models/matey.rb +4 -0
  294. data/test/models/member.rb +12 -0
  295. data/test/models/member_detail.rb +5 -0
  296. data/test/models/member_type.rb +3 -0
  297. data/test/models/membership.rb +9 -0
  298. data/test/models/minimalistic.rb +2 -0
  299. data/test/models/mixed_case_monkey.rb +3 -0
  300. data/test/models/movie.rb +5 -0
  301. data/test/models/order.rb +4 -0
  302. data/test/models/organization.rb +6 -0
  303. data/test/models/owner.rb +5 -0
  304. data/test/models/parrot.rb +16 -0
  305. data/test/models/person.rb +16 -0
  306. data/test/models/pet.rb +5 -0
  307. data/test/models/pirate.rb +70 -0
  308. data/test/models/post.rb +100 -0
  309. data/test/models/price_estimate.rb +3 -0
  310. data/test/models/project.rb +30 -0
  311. data/test/models/reader.rb +4 -0
  312. data/test/models/reference.rb +4 -0
  313. data/test/models/reply.rb +46 -0
  314. data/test/models/ship.rb +10 -0
  315. data/test/models/ship_part.rb +5 -0
  316. data/test/models/sponsor.rb +4 -0
  317. data/test/models/subject.rb +4 -0
  318. data/test/models/subscriber.rb +8 -0
  319. data/test/models/subscription.rb +4 -0
  320. data/test/models/tag.rb +7 -0
  321. data/test/models/tagging.rb +10 -0
  322. data/test/models/task.rb +3 -0
  323. data/test/models/topic.rb +80 -0
  324. data/test/models/toy.rb +6 -0
  325. data/test/models/treasure.rb +8 -0
  326. data/test/models/vertex.rb +9 -0
  327. data/test/models/warehouse_thing.rb +5 -0
  328. data/test/schema/mysql_specific_schema.rb +24 -0
  329. data/test/schema/postgresql_specific_schema.rb +114 -0
  330. data/test/schema/schema.rb +493 -0
  331. data/test/schema/schema2.rb +6 -0
  332. data/test/schema/sqlite_specific_schema.rb +25 -0
  333. metadata +420 -0
@@ -0,0 +1,1134 @@
1
+ require "cases/helper"
2
+ require 'models/developer'
3
+ require 'models/project'
4
+ require 'models/company'
5
+ require 'models/topic'
6
+ require 'models/reply'
7
+ require 'models/category'
8
+ require 'models/post'
9
+ require 'models/author'
10
+ require 'models/comment'
11
+ require 'models/person'
12
+ require 'models/reader'
13
+ require 'models/tagging'
14
+
15
+ class HasManyAssociationsTest < ActiveRecord::TestCase
16
+ fixtures :accounts, :categories, :companies, :developers, :projects,
17
+ :developers_projects, :topics, :authors, :comments, :author_addresses,
18
+ :people, :posts, :readers, :taggings
19
+
20
+ def setup
21
+ Client.destroyed_client_ids.clear
22
+ end
23
+
24
+ def force_signal37_to_load_all_clients_of_firm
25
+ companies(:first_firm).clients_of_firm.each {|f| }
26
+ end
27
+
28
+ def test_counting_with_counter_sql
29
+ assert_equal 2, Firm.find(:first).clients.count
30
+ end
31
+
32
+ def test_counting
33
+ assert_equal 2, Firm.find(:first).plain_clients.count
34
+ end
35
+
36
+ def test_counting_with_empty_hash_conditions
37
+ assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => {})
38
+ end
39
+
40
+ def test_counting_with_single_conditions
41
+ assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => ['name=?', "Microsoft"])
42
+ end
43
+
44
+ def test_counting_with_single_hash
45
+ assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => {:name => "Microsoft"})
46
+ end
47
+
48
+ def test_counting_with_column_name_and_hash
49
+ assert_equal 2, Firm.find(:first).plain_clients.count(:name)
50
+ end
51
+
52
+ def test_counting_with_association_limit
53
+ firm = companies(:first_firm)
54
+ assert_equal firm.limited_clients.length, firm.limited_clients.size
55
+ assert_equal firm.limited_clients.length, firm.limited_clients.count
56
+ end
57
+
58
+ def test_finding
59
+ assert_equal 2, Firm.find(:first).clients.length
60
+ end
61
+
62
+ def test_find_with_blank_conditions
63
+ [[], {}, nil, ""].each do |blank|
64
+ assert_equal 2, Firm.find(:first).clients.find(:all, :conditions => blank).size
65
+ end
66
+ end
67
+
68
+ def test_find_many_with_merged_options
69
+ assert_equal 1, companies(:first_firm).limited_clients.size
70
+ assert_equal 1, companies(:first_firm).limited_clients.find(:all).size
71
+ assert_equal 2, companies(:first_firm).limited_clients.find(:all, :limit => nil).size
72
+ end
73
+
74
+ def test_dynamic_find_last_without_specified_order
75
+ assert_equal companies(:second_client), companies(:first_firm).unsorted_clients.find_last_by_type('Client')
76
+ end
77
+
78
+ def test_dynamic_find_should_respect_association_order
79
+ assert_equal companies(:second_client), companies(:first_firm).clients_sorted_desc.find(:first, :conditions => "type = 'Client'")
80
+ assert_equal companies(:second_client), companies(:first_firm).clients_sorted_desc.find_by_type('Client')
81
+ end
82
+
83
+ def test_dynamic_find_order_should_override_association_order
84
+ assert_equal companies(:first_client), companies(:first_firm).clients_sorted_desc.find(:first, :conditions => "type = 'Client'", :order => 'id')
85
+ assert_equal companies(:first_client), companies(:first_firm).clients_sorted_desc.find_by_type('Client', :order => 'id')
86
+ end
87
+
88
+ def test_dynamic_find_all_should_respect_association_order
89
+ assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.find(:all, :conditions => "type = 'Client'")
90
+ assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.find_all_by_type('Client')
91
+ end
92
+
93
+ def test_dynamic_find_all_order_should_override_association_order
94
+ assert_equal [companies(:first_client), companies(:second_client)], companies(:first_firm).clients_sorted_desc.find(:all, :conditions => "type = 'Client'", :order => 'id')
95
+ assert_equal [companies(:first_client), companies(:second_client)], companies(:first_firm).clients_sorted_desc.find_all_by_type('Client', :order => 'id')
96
+ end
97
+
98
+ def test_dynamic_find_all_should_respect_association_limit
99
+ assert_equal 1, companies(:first_firm).limited_clients.find(:all, :conditions => "type = 'Client'").length
100
+ assert_equal 1, companies(:first_firm).limited_clients.find_all_by_type('Client').length
101
+ end
102
+
103
+ def test_dynamic_find_all_limit_should_override_association_limit
104
+ assert_equal 2, companies(:first_firm).limited_clients.find(:all, :conditions => "type = 'Client'", :limit => 9_000).length
105
+ assert_equal 2, companies(:first_firm).limited_clients.find_all_by_type('Client', :limit => 9_000).length
106
+ end
107
+
108
+ def test_dynamic_find_all_should_respect_readonly_access
109
+ companies(:first_firm).readonly_clients.find(:all).each { |c| assert_raise(ActiveRecord::ReadOnlyRecord) { c.save! } }
110
+ companies(:first_firm).readonly_clients.find(:all).each { |c| assert c.readonly? }
111
+ end
112
+
113
+ def test_cant_save_has_many_readonly_association
114
+ authors(:david).readonly_comments.each { |c| assert_raise(ActiveRecord::ReadOnlyRecord) { c.save! } }
115
+ authors(:david).readonly_comments.each { |c| assert c.readonly? }
116
+ end
117
+
118
+ def test_triple_equality
119
+ assert !(Array === Firm.find(:first).clients)
120
+ assert Firm.find(:first).clients === Array
121
+ end
122
+
123
+ def test_finding_default_orders
124
+ assert_equal "Summit", Firm.find(:first).clients.first.name
125
+ end
126
+
127
+ def test_finding_with_different_class_name_and_order
128
+ assert_equal "Microsoft", Firm.find(:first).clients_sorted_desc.first.name
129
+ end
130
+
131
+ def test_finding_with_foreign_key
132
+ assert_equal "Microsoft", Firm.find(:first).clients_of_firm.first.name
133
+ end
134
+
135
+ def test_finding_with_condition
136
+ assert_equal "Microsoft", Firm.find(:first).clients_like_ms.first.name
137
+ end
138
+
139
+ def test_finding_with_condition_hash
140
+ assert_equal "Microsoft", Firm.find(:first).clients_like_ms_with_hash_conditions.first.name
141
+ end
142
+
143
+ def test_finding_using_primary_key
144
+ assert_equal "Summit", Firm.find(:first).clients_using_primary_key.first.name
145
+ end
146
+
147
+ def test_finding_using_sql
148
+ firm = Firm.find(:first)
149
+ first_client = firm.clients_using_sql.first
150
+ assert_not_nil first_client
151
+ assert_equal "Microsoft", first_client.name
152
+ assert_equal 1, firm.clients_using_sql.size
153
+ assert_equal 1, Firm.find(:first).clients_using_sql.size
154
+ end
155
+
156
+ def test_counting_using_sql
157
+ assert_equal 1, Firm.find(:first).clients_using_counter_sql.size
158
+ assert Firm.find(:first).clients_using_counter_sql.any?
159
+ assert_equal 0, Firm.find(:first).clients_using_zero_counter_sql.size
160
+ assert !Firm.find(:first).clients_using_zero_counter_sql.any?
161
+ end
162
+
163
+ def test_counting_non_existant_items_using_sql
164
+ assert_equal 0, Firm.find(:first).no_clients_using_counter_sql.size
165
+ end
166
+
167
+ def test_belongs_to_sanity
168
+ c = Client.new
169
+ assert_nil c.firm
170
+
171
+ if c.firm
172
+ assert false, "belongs_to failed if check"
173
+ end
174
+
175
+ unless c.firm
176
+ else
177
+ assert false, "belongs_to failed unless check"
178
+ end
179
+ end
180
+
181
+ def test_find_ids
182
+ firm = Firm.find(:first)
183
+
184
+ assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find }
185
+
186
+ client = firm.clients.find(2)
187
+ assert_kind_of Client, client
188
+
189
+ client_ary = firm.clients.find([2])
190
+ assert_kind_of Array, client_ary
191
+ assert_equal client, client_ary.first
192
+
193
+ client_ary = firm.clients.find(2, 3)
194
+ assert_kind_of Array, client_ary
195
+ assert_equal 2, client_ary.size
196
+ assert_equal client, client_ary.first
197
+
198
+ assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(2, 99) }
199
+ end
200
+
201
+ def test_find_string_ids_when_using_finder_sql
202
+ firm = Firm.find(:first)
203
+
204
+ client = firm.clients_using_finder_sql.find("2")
205
+ assert_kind_of Client, client
206
+
207
+ client_ary = firm.clients_using_finder_sql.find(["2"])
208
+ assert_kind_of Array, client_ary
209
+ assert_equal client, client_ary.first
210
+
211
+ client_ary = firm.clients_using_finder_sql.find("2", "3")
212
+ assert_kind_of Array, client_ary
213
+ assert_equal 2, client_ary.size
214
+ assert client_ary.include?(client)
215
+ end
216
+
217
+ def test_find_all
218
+ firm = Firm.find(:first)
219
+ assert_equal 2, firm.clients.find(:all, :conditions => "#{QUOTED_TYPE} = 'Client'").length
220
+ assert_equal 1, firm.clients.find(:all, :conditions => "name = 'Summit'").length
221
+ end
222
+
223
+ def test_find_each
224
+ firm = companies(:first_firm)
225
+
226
+ assert ! firm.clients.loaded?
227
+
228
+ assert_queries(3) do
229
+ firm.clients.find_each(:batch_size => 1) {|c| assert_equal firm.id, c.firm_id }
230
+ end
231
+
232
+ assert ! firm.clients.loaded?
233
+ end
234
+
235
+ def test_find_each_with_conditions
236
+ firm = companies(:first_firm)
237
+
238
+ assert_queries(2) do
239
+ firm.clients.find_each(:batch_size => 1, :conditions => {:name => "Microsoft"}) do |c|
240
+ assert_equal firm.id, c.firm_id
241
+ assert_equal "Microsoft", c.name
242
+ end
243
+ end
244
+
245
+ assert ! firm.clients.loaded?
246
+ end
247
+
248
+ def test_find_in_batches
249
+ firm = companies(:first_firm)
250
+
251
+ assert ! firm.clients.loaded?
252
+
253
+ assert_queries(2) do
254
+ firm.clients.find_in_batches(:batch_size => 2) do |clients|
255
+ clients.each {|c| assert_equal firm.id, c.firm_id }
256
+ end
257
+ end
258
+
259
+ assert ! firm.clients.loaded?
260
+ end
261
+
262
+ def test_find_all_sanitized
263
+ firm = Firm.find(:first)
264
+ summit = firm.clients.find(:all, :conditions => "name = 'Summit'")
265
+ assert_equal summit, firm.clients.find(:all, :conditions => ["name = ?", "Summit"])
266
+ assert_equal summit, firm.clients.find(:all, :conditions => ["name = :name", { :name => "Summit" }])
267
+ end
268
+
269
+ def test_find_first
270
+ firm = Firm.find(:first)
271
+ client2 = Client.find(2)
272
+ assert_equal firm.clients.first, firm.clients.find(:first)
273
+ assert_equal client2, firm.clients.find(:first, :conditions => "#{QUOTED_TYPE} = 'Client'")
274
+ end
275
+
276
+ def test_find_first_sanitized
277
+ firm = Firm.find(:first)
278
+ client2 = Client.find(2)
279
+ assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = ?", 'Client'])
280
+ assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }])
281
+ end
282
+
283
+ def test_find_all_with_include_and_conditions
284
+ assert_nothing_raised do
285
+ Developer.find(:all, :joins => :audit_logs, :conditions => {'audit_logs.message' => nil, :name => 'Smith'})
286
+ end
287
+ end
288
+
289
+ def test_find_in_collection
290
+ assert_equal Client.find(2).name, companies(:first_firm).clients.find(2).name
291
+ assert_raise(ActiveRecord::RecordNotFound) { companies(:first_firm).clients.find(6) }
292
+ end
293
+
294
+ def test_find_grouped
295
+ all_clients_of_firm1 = Client.find(:all, :conditions => "firm_id = 1")
296
+ grouped_clients_of_firm1 = Client.find(:all, :conditions => "firm_id = 1", :group => "firm_id", :select => 'firm_id, count(id) as clients_count')
297
+ assert_equal 2, all_clients_of_firm1.size
298
+ assert_equal 1, grouped_clients_of_firm1.size
299
+ end
300
+
301
+ def test_find_scoped_grouped
302
+ assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.size
303
+ assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.length
304
+ assert_equal 2, companies(:first_firm).clients_grouped_by_name.size
305
+ assert_equal 2, companies(:first_firm).clients_grouped_by_name.length
306
+ end
307
+
308
+ def test_find_scoped_grouped_having
309
+ assert_equal 1, authors(:david).popular_grouped_posts.length
310
+ assert_equal 0, authors(:mary).popular_grouped_posts.length
311
+ end
312
+
313
+ def test_adding
314
+ force_signal37_to_load_all_clients_of_firm
315
+ natural = Client.new("name" => "Natural Company")
316
+ companies(:first_firm).clients_of_firm << natural
317
+ assert_equal 2, companies(:first_firm).clients_of_firm.size # checking via the collection
318
+ assert_equal 2, companies(:first_firm).clients_of_firm(true).size # checking using the db
319
+ assert_equal natural, companies(:first_firm).clients_of_firm.last
320
+ end
321
+
322
+ def test_adding_using_create
323
+ first_firm = companies(:first_firm)
324
+ assert_equal 2, first_firm.plain_clients.size
325
+ natural = first_firm.plain_clients.create(:name => "Natural Company")
326
+ assert_equal 3, first_firm.plain_clients.length
327
+ assert_equal 3, first_firm.plain_clients.size
328
+ end
329
+
330
+ def test_create_with_bang_on_has_many_when_parent_is_new_raises
331
+ assert_raise(ActiveRecord::RecordNotSaved) do
332
+ firm = Firm.new
333
+ firm.plain_clients.create! :name=>"Whoever"
334
+ end
335
+ end
336
+
337
+ def test_regular_create_on_has_many_when_parent_is_new_raises
338
+ assert_raise(ActiveRecord::RecordNotSaved) do
339
+ firm = Firm.new
340
+ firm.plain_clients.create :name=>"Whoever"
341
+ end
342
+ end
343
+
344
+ def test_create_with_bang_on_has_many_raises_when_record_not_saved
345
+ assert_raise(ActiveRecord::RecordInvalid) do
346
+ firm = Firm.find(:first)
347
+ firm.plain_clients.create!
348
+ end
349
+ end
350
+
351
+ def test_create_with_bang_on_habtm_when_parent_is_new_raises
352
+ assert_raise(ActiveRecord::RecordNotSaved) do
353
+ Developer.new("name" => "Aredridel").projects.create!
354
+ end
355
+ end
356
+
357
+ def test_adding_a_mismatch_class
358
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << nil }
359
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << 1 }
360
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << Topic.find(1) }
361
+ end
362
+
363
+ def test_adding_a_collection
364
+ force_signal37_to_load_all_clients_of_firm
365
+ companies(:first_firm).clients_of_firm.concat([Client.new("name" => "Natural Company"), Client.new("name" => "Apple")])
366
+ assert_equal 3, companies(:first_firm).clients_of_firm.size
367
+ assert_equal 3, companies(:first_firm).clients_of_firm(true).size
368
+ end
369
+
370
+ def test_build
371
+ company = companies(:first_firm)
372
+ new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") }
373
+ assert !company.clients_of_firm.loaded?
374
+
375
+ assert_equal "Another Client", new_client.name
376
+ assert new_client.new_record?
377
+ assert_equal new_client, company.clients_of_firm.last
378
+ end
379
+
380
+ def test_collection_size_after_building
381
+ company = companies(:first_firm) # company already has one client
382
+ company.clients_of_firm.build("name" => "Another Client")
383
+ company.clients_of_firm.build("name" => "Yet Another Client")
384
+ assert_equal 3, company.clients_of_firm.size
385
+ end
386
+
387
+ def test_collection_size_twice_for_regressions
388
+ post = posts(:thinking)
389
+ assert_equal 0, post.readers.size
390
+ # This test needs a post that has no readers, we assert it to ensure it holds,
391
+ # but need to reload the post because the very call to #size hides the bug.
392
+ post.reload
393
+ post.readers.build
394
+ size1 = post.readers.size
395
+ size2 = post.readers.size
396
+ assert_equal size1, size2
397
+ end
398
+
399
+ def test_build_many
400
+ company = companies(:first_firm)
401
+ new_clients = assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) }
402
+ assert_equal 2, new_clients.size
403
+ end
404
+
405
+ def test_build_followed_by_save_does_not_load_target
406
+ new_client = companies(:first_firm).clients_of_firm.build("name" => "Another Client")
407
+ assert companies(:first_firm).save
408
+ assert !companies(:first_firm).clients_of_firm.loaded?
409
+ end
410
+
411
+ def test_build_without_loading_association
412
+ first_topic = topics(:first)
413
+ Reply.column_names
414
+
415
+ assert_equal 1, first_topic.replies.length
416
+
417
+ assert_no_queries do
418
+ first_topic.replies.build(:title => "Not saved", :content => "Superstars")
419
+ assert_equal 2, first_topic.replies.size
420
+ end
421
+
422
+ assert_equal 2, first_topic.replies.to_ary.size
423
+ end
424
+
425
+ def test_build_via_block
426
+ company = companies(:first_firm)
427
+ new_client = assert_no_queries { company.clients_of_firm.build {|client| client.name = "Another Client" } }
428
+ assert !company.clients_of_firm.loaded?
429
+
430
+ assert_equal "Another Client", new_client.name
431
+ assert new_client.new_record?
432
+ assert_equal new_client, company.clients_of_firm.last
433
+ end
434
+
435
+ def test_build_many_via_block
436
+ company = companies(:first_firm)
437
+ new_clients = assert_no_queries do
438
+ company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client|
439
+ client.name = "changed"
440
+ end
441
+ end
442
+
443
+ assert_equal 2, new_clients.size
444
+ assert_equal "changed", new_clients.first.name
445
+ assert_equal "changed", new_clients.last.name
446
+ end
447
+
448
+ def test_create_without_loading_association
449
+ first_firm = companies(:first_firm)
450
+ Firm.column_names
451
+ Client.column_names
452
+
453
+ assert_equal 1, first_firm.clients_of_firm.size
454
+ first_firm.clients_of_firm.reset
455
+
456
+ assert_queries(1) do
457
+ first_firm.clients_of_firm.create(:name => "Superstars")
458
+ end
459
+
460
+ assert_equal 2, first_firm.clients_of_firm.size
461
+ end
462
+
463
+ def test_create
464
+ force_signal37_to_load_all_clients_of_firm
465
+ new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client")
466
+ assert !new_client.new_record?
467
+ assert_equal new_client, companies(:first_firm).clients_of_firm.last
468
+ assert_equal new_client, companies(:first_firm).clients_of_firm(true).last
469
+ end
470
+
471
+ def test_create_many
472
+ companies(:first_firm).clients_of_firm.create([{"name" => "Another Client"}, {"name" => "Another Client II"}])
473
+ assert_equal 3, companies(:first_firm).clients_of_firm(true).size
474
+ end
475
+
476
+ def test_create_followed_by_save_does_not_load_target
477
+ new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client")
478
+ assert companies(:first_firm).save
479
+ assert !companies(:first_firm).clients_of_firm.loaded?
480
+ end
481
+
482
+ def test_find_or_initialize
483
+ the_client = companies(:first_firm).clients.find_or_initialize_by_name("Yet another client")
484
+ assert_equal companies(:first_firm).id, the_client.firm_id
485
+ assert_equal "Yet another client", the_client.name
486
+ assert the_client.new_record?
487
+ end
488
+
489
+ def test_find_or_create
490
+ number_of_clients = companies(:first_firm).clients.size
491
+ the_client = companies(:first_firm).clients.find_or_create_by_name("Yet another client")
492
+ assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size
493
+ assert_equal the_client, companies(:first_firm).clients.find_or_create_by_name("Yet another client")
494
+ assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size
495
+ end
496
+
497
+ def test_deleting
498
+ force_signal37_to_load_all_clients_of_firm
499
+ companies(:first_firm).clients_of_firm.delete(companies(:first_firm).clients_of_firm.first)
500
+ assert_equal 0, companies(:first_firm).clients_of_firm.size
501
+ assert_equal 0, companies(:first_firm).clients_of_firm(true).size
502
+ end
503
+
504
+ def test_deleting_before_save
505
+ new_firm = Firm.new("name" => "A New Firm, Inc.")
506
+ new_client = new_firm.clients_of_firm.build("name" => "Another Client")
507
+ assert_equal 1, new_firm.clients_of_firm.size
508
+ new_firm.clients_of_firm.delete(new_client)
509
+ assert_equal 0, new_firm.clients_of_firm.size
510
+ end
511
+
512
+ def test_deleting_updates_counter_cache
513
+ topic = Topic.first
514
+ assert_equal topic.replies.to_a.size, topic.replies_count
515
+
516
+ topic.replies.delete(topic.replies.first)
517
+ topic.reload
518
+ assert_equal topic.replies.to_a.size, topic.replies_count
519
+ end
520
+
521
+ def test_deleting_updates_counter_cache_without_dependent_destroy
522
+ post = posts(:welcome)
523
+
524
+ assert_difference "post.reload.taggings_count", -1 do
525
+ post.taggings.delete(post.taggings.first)
526
+ end
527
+ end
528
+
529
+ def test_deleting_a_collection
530
+ force_signal37_to_load_all_clients_of_firm
531
+ companies(:first_firm).clients_of_firm.create("name" => "Another Client")
532
+ assert_equal 2, companies(:first_firm).clients_of_firm.size
533
+ companies(:first_firm).clients_of_firm.delete([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1]])
534
+ assert_equal 0, companies(:first_firm).clients_of_firm.size
535
+ assert_equal 0, companies(:first_firm).clients_of_firm(true).size
536
+ end
537
+
538
+ def test_delete_all
539
+ force_signal37_to_load_all_clients_of_firm
540
+ companies(:first_firm).clients_of_firm.create("name" => "Another Client")
541
+ assert_equal 2, companies(:first_firm).clients_of_firm.size
542
+ companies(:first_firm).clients_of_firm.delete_all
543
+ assert_equal 0, companies(:first_firm).clients_of_firm.size
544
+ assert_equal 0, companies(:first_firm).clients_of_firm(true).size
545
+ end
546
+
547
+ def test_delete_all_with_not_yet_loaded_association_collection
548
+ force_signal37_to_load_all_clients_of_firm
549
+ companies(:first_firm).clients_of_firm.create("name" => "Another Client")
550
+ assert_equal 2, companies(:first_firm).clients_of_firm.size
551
+ companies(:first_firm).clients_of_firm.reset
552
+ companies(:first_firm).clients_of_firm.delete_all
553
+ assert_equal 0, companies(:first_firm).clients_of_firm.size
554
+ assert_equal 0, companies(:first_firm).clients_of_firm(true).size
555
+ end
556
+
557
+ def test_clearing_an_association_collection
558
+ firm = companies(:first_firm)
559
+ client_id = firm.clients_of_firm.first.id
560
+ assert_equal 1, firm.clients_of_firm.size
561
+
562
+ firm.clients_of_firm.clear
563
+
564
+ assert_equal 0, firm.clients_of_firm.size
565
+ assert_equal 0, firm.clients_of_firm(true).size
566
+ assert_equal [], Client.destroyed_client_ids[firm.id]
567
+
568
+ # Should not be destroyed since the association is not dependent.
569
+ assert_nothing_raised do
570
+ assert Client.find(client_id).firm.nil?
571
+ end
572
+ end
573
+
574
+ def test_clearing_updates_counter_cache
575
+ topic = Topic.first
576
+
577
+ topic.replies.clear
578
+ topic.reload
579
+ assert_equal 0, topic.replies_count
580
+ end
581
+
582
+ def test_clearing_a_dependent_association_collection
583
+ firm = companies(:first_firm)
584
+ client_id = firm.dependent_clients_of_firm.first.id
585
+ assert_equal 1, firm.dependent_clients_of_firm.size
586
+
587
+ # :dependent means destroy is called on each client
588
+ firm.dependent_clients_of_firm.clear
589
+
590
+ assert_equal 0, firm.dependent_clients_of_firm.size
591
+ assert_equal 0, firm.dependent_clients_of_firm(true).size
592
+ assert_equal [client_id], Client.destroyed_client_ids[firm.id]
593
+
594
+ # Should be destroyed since the association is dependent.
595
+ assert Client.find_by_id(client_id).nil?
596
+ end
597
+
598
+ def test_clearing_an_exclusively_dependent_association_collection
599
+ firm = companies(:first_firm)
600
+ client_id = firm.exclusively_dependent_clients_of_firm.first.id
601
+ assert_equal 1, firm.exclusively_dependent_clients_of_firm.size
602
+
603
+ assert_equal [], Client.destroyed_client_ids[firm.id]
604
+
605
+ # :exclusively_dependent means each client is deleted directly from
606
+ # the database without looping through them calling destroy.
607
+ firm.exclusively_dependent_clients_of_firm.clear
608
+
609
+ assert_equal 0, firm.exclusively_dependent_clients_of_firm.size
610
+ assert_equal 0, firm.exclusively_dependent_clients_of_firm(true).size
611
+ # no destroy-filters should have been called
612
+ assert_equal [], Client.destroyed_client_ids[firm.id]
613
+
614
+ # Should be destroyed since the association is exclusively dependent.
615
+ assert Client.find_by_id(client_id).nil?
616
+ end
617
+
618
+ def test_dependent_association_respects_optional_conditions_on_delete
619
+ firm = companies(:odegy)
620
+ Client.create(:client_of => firm.id, :name => "BigShot Inc.")
621
+ Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
622
+ # only one of two clients is included in the association due to the :conditions key
623
+ assert_equal 2, Client.find_all_by_client_of(firm.id).size
624
+ assert_equal 1, firm.dependent_conditional_clients_of_firm.size
625
+ firm.destroy
626
+ # only the correctly associated client should have been deleted
627
+ assert_equal 1, Client.find_all_by_client_of(firm.id).size
628
+ end
629
+
630
+ def test_dependent_association_respects_optional_sanitized_conditions_on_delete
631
+ firm = companies(:odegy)
632
+ Client.create(:client_of => firm.id, :name => "BigShot Inc.")
633
+ Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
634
+ # only one of two clients is included in the association due to the :conditions key
635
+ assert_equal 2, Client.find_all_by_client_of(firm.id).size
636
+ assert_equal 1, firm.dependent_sanitized_conditional_clients_of_firm.size
637
+ firm.destroy
638
+ # only the correctly associated client should have been deleted
639
+ assert_equal 1, Client.find_all_by_client_of(firm.id).size
640
+ end
641
+
642
+ def test_dependent_association_respects_optional_hash_conditions_on_delete
643
+ firm = companies(:odegy)
644
+ Client.create(:client_of => firm.id, :name => "BigShot Inc.")
645
+ Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
646
+ # only one of two clients is included in the association due to the :conditions key
647
+ assert_equal 2, Client.find_all_by_client_of(firm.id).size
648
+ assert_equal 1, firm.dependent_sanitized_conditional_clients_of_firm.size
649
+ firm.destroy
650
+ # only the correctly associated client should have been deleted
651
+ assert_equal 1, Client.find_all_by_client_of(firm.id).size
652
+ end
653
+
654
+ def test_delete_all_association_with_primary_key_deletes_correct_records
655
+ firm = Firm.find(:first)
656
+ # break the vanilla firm_id foreign key
657
+ assert_equal 2, firm.clients.count
658
+ firm.clients.first.update_attribute(:firm_id, nil)
659
+ assert_equal 1, firm.clients(true).count
660
+ assert_equal 1, firm.clients_using_primary_key_with_delete_all.count
661
+ old_record = firm.clients_using_primary_key_with_delete_all.first
662
+ firm = Firm.find(:first)
663
+ firm.destroy
664
+ assert Client.find_by_id(old_record.id).nil?
665
+ end
666
+
667
+ def test_creation_respects_hash_condition
668
+ ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.build
669
+
670
+ assert ms_client.save
671
+ assert_equal 'Microsoft', ms_client.name
672
+
673
+ another_ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.create
674
+
675
+ assert !another_ms_client.new_record?
676
+ assert_equal 'Microsoft', another_ms_client.name
677
+ end
678
+
679
+ def test_dependent_delete_and_destroy_with_belongs_to
680
+ author_address = author_addresses(:david_address)
681
+ assert_equal [], AuthorAddress.destroyed_author_address_ids[authors(:david).id]
682
+
683
+ assert_difference "AuthorAddress.count", -2 do
684
+ authors(:david).destroy
685
+ end
686
+
687
+ assert_equal nil, AuthorAddress.find_by_id(authors(:david).author_address_id)
688
+ assert_equal nil, AuthorAddress.find_by_id(authors(:david).author_address_extra_id)
689
+ end
690
+
691
+ def test_invalid_belongs_to_dependent_option_raises_exception
692
+ assert_raise ArgumentError do
693
+ Author.belongs_to :special_author_address, :dependent => :nullify
694
+ end
695
+ end
696
+
697
+ def test_clearing_without_initial_access
698
+ firm = companies(:first_firm)
699
+
700
+ firm.clients_of_firm.clear
701
+
702
+ assert_equal 0, firm.clients_of_firm.size
703
+ assert_equal 0, firm.clients_of_firm(true).size
704
+ end
705
+
706
+ def test_deleting_a_item_which_is_not_in_the_collection
707
+ force_signal37_to_load_all_clients_of_firm
708
+ summit = Client.find_by_name('Summit')
709
+ companies(:first_firm).clients_of_firm.delete(summit)
710
+ assert_equal 1, companies(:first_firm).clients_of_firm.size
711
+ assert_equal 1, companies(:first_firm).clients_of_firm(true).size
712
+ assert_equal 2, summit.client_of
713
+ end
714
+
715
+ def test_deleting_type_mismatch
716
+ david = Developer.find(1)
717
+ david.projects.reload
718
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(1) }
719
+ end
720
+
721
+ def test_deleting_self_type_mismatch
722
+ david = Developer.find(1)
723
+ david.projects.reload
724
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(Project.find(1).developers) }
725
+ end
726
+
727
+ def test_destroying
728
+ force_signal37_to_load_all_clients_of_firm
729
+
730
+ assert_difference "Client.count", -1 do
731
+ companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first)
732
+ end
733
+
734
+ assert_equal 0, companies(:first_firm).reload.clients_of_firm.size
735
+ assert_equal 0, companies(:first_firm).clients_of_firm(true).size
736
+ end
737
+
738
+ def test_destroying_by_fixnum_id
739
+ force_signal37_to_load_all_clients_of_firm
740
+
741
+ assert_difference "Client.count", -1 do
742
+ companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first.id)
743
+ end
744
+
745
+ assert_equal 0, companies(:first_firm).reload.clients_of_firm.size
746
+ assert_equal 0, companies(:first_firm).clients_of_firm(true).size
747
+ end
748
+
749
+ def test_destroying_by_string_id
750
+ force_signal37_to_load_all_clients_of_firm
751
+
752
+ assert_difference "Client.count", -1 do
753
+ companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first.id.to_s)
754
+ end
755
+
756
+ assert_equal 0, companies(:first_firm).reload.clients_of_firm.size
757
+ assert_equal 0, companies(:first_firm).clients_of_firm(true).size
758
+ end
759
+
760
+ def test_destroying_a_collection
761
+ force_signal37_to_load_all_clients_of_firm
762
+ companies(:first_firm).clients_of_firm.create("name" => "Another Client")
763
+ assert_equal 2, companies(:first_firm).clients_of_firm.size
764
+
765
+ assert_difference "Client.count", -2 do
766
+ companies(:first_firm).clients_of_firm.destroy([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1]])
767
+ end
768
+
769
+ assert_equal 0, companies(:first_firm).reload.clients_of_firm.size
770
+ assert_equal 0, companies(:first_firm).clients_of_firm(true).size
771
+ end
772
+
773
+ def test_destroy_all
774
+ force_signal37_to_load_all_clients_of_firm
775
+ assert !companies(:first_firm).clients_of_firm.empty?, "37signals has clients after load"
776
+ companies(:first_firm).clients_of_firm.destroy_all
777
+ assert companies(:first_firm).clients_of_firm.empty?, "37signals has no clients after destroy all"
778
+ assert companies(:first_firm).clients_of_firm(true).empty?, "37signals has no clients after destroy all and refresh"
779
+ end
780
+
781
+ def test_dependence
782
+ firm = companies(:first_firm)
783
+ assert_equal 2, firm.clients.size
784
+ firm.destroy
785
+ assert Client.find(:all, :conditions => "firm_id=#{firm.id}").empty?
786
+ end
787
+
788
+ def test_dependence_for_associations_with_hash_condition
789
+ david = authors(:david)
790
+ post = posts(:thinking).id
791
+ assert_difference('Post.count', -1) { assert david.destroy }
792
+ end
793
+
794
+ def test_destroy_dependent_when_deleted_from_association
795
+ firm = Firm.find(:first)
796
+ assert_equal 2, firm.clients.size
797
+
798
+ client = firm.clients.first
799
+ firm.clients.delete(client)
800
+
801
+ assert_raise(ActiveRecord::RecordNotFound) { Client.find(client.id) }
802
+ assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(client.id) }
803
+ assert_equal 1, firm.clients.size
804
+ end
805
+
806
+ def test_three_levels_of_dependence
807
+ topic = Topic.create "title" => "neat and simple"
808
+ reply = topic.replies.create "title" => "neat and simple", "content" => "still digging it"
809
+ silly_reply = reply.replies.create "title" => "neat and simple", "content" => "ain't complaining"
810
+
811
+ assert_nothing_raised { topic.destroy }
812
+ end
813
+
814
+ uses_transaction :test_dependence_with_transaction_support_on_failure
815
+ def test_dependence_with_transaction_support_on_failure
816
+ firm = companies(:first_firm)
817
+ clients = firm.clients
818
+ assert_equal 2, clients.length
819
+ clients.last.instance_eval { def before_destroy() raise "Trigger rollback" end }
820
+
821
+ firm.destroy rescue "do nothing"
822
+
823
+ assert_equal 2, Client.find(:all, :conditions => "firm_id=#{firm.id}").size
824
+ end
825
+
826
+ def test_dependence_on_account
827
+ num_accounts = Account.count
828
+ companies(:first_firm).destroy
829
+ assert_equal num_accounts - 1, Account.count
830
+ end
831
+
832
+ def test_depends_and_nullify
833
+ num_accounts = Account.count
834
+ num_companies = Company.count
835
+
836
+ core = companies(:rails_core)
837
+ assert_equal accounts(:rails_core_account), core.account
838
+ assert_equal companies(:leetsoft, :jadedpixel), core.companies
839
+ core.destroy
840
+ assert_nil accounts(:rails_core_account).reload.firm_id
841
+ assert_nil companies(:leetsoft).reload.client_of
842
+ assert_nil companies(:jadedpixel).reload.client_of
843
+
844
+
845
+ assert_equal num_accounts, Account.count
846
+ end
847
+
848
+ def test_included_in_collection
849
+ assert companies(:first_firm).clients.include?(Client.find(2))
850
+ end
851
+
852
+ def test_adding_array_and_collection
853
+ assert_nothing_raised { Firm.find(:first).clients + Firm.find(:all).last.clients }
854
+ end
855
+
856
+ def test_find_all_without_conditions
857
+ firm = companies(:first_firm)
858
+ assert_equal 2, firm.clients.find(:all).length
859
+ end
860
+
861
+ def test_replace_with_less
862
+ firm = Firm.find(:first)
863
+ firm.clients = [companies(:first_client)]
864
+ assert firm.save, "Could not save firm"
865
+ firm.reload
866
+ assert_equal 1, firm.clients.length
867
+ end
868
+
869
+ def test_replace_with_less_and_dependent_nullify
870
+ num_companies = Company.count
871
+ companies(:rails_core).companies = []
872
+ assert_equal num_companies, Company.count
873
+ end
874
+
875
+ def test_replace_with_new
876
+ firm = Firm.find(:first)
877
+ firm.clients = [companies(:second_client), Client.new("name" => "New Client")]
878
+ firm.save
879
+ firm.reload
880
+ assert_equal 2, firm.clients.length
881
+ assert !firm.clients.include?(:first_client)
882
+ end
883
+
884
+ def test_get_ids
885
+ assert_equal [companies(:first_client).id, companies(:second_client).id], companies(:first_firm).client_ids
886
+ end
887
+
888
+ def test_get_ids_for_loaded_associations
889
+ company = companies(:first_firm)
890
+ company.clients(true)
891
+ assert_queries(0) do
892
+ company.client_ids
893
+ company.client_ids
894
+ end
895
+ end
896
+
897
+ def test_get_ids_for_unloaded_associations_does_not_load_them
898
+ company = companies(:first_firm)
899
+ assert !company.clients.loaded?
900
+ assert_equal [companies(:first_client).id, companies(:second_client).id], company.client_ids
901
+ assert !company.clients.loaded?
902
+ end
903
+
904
+ def test_get_ids_for_unloaded_finder_sql_associations_loads_them
905
+ company = companies(:first_firm)
906
+ assert !company.clients_using_sql.loaded?
907
+ assert_equal [companies(:second_client).id], company.clients_using_sql_ids
908
+ assert company.clients_using_sql.loaded?
909
+ end
910
+
911
+ def test_assign_ids_ignoring_blanks
912
+ firm = Firm.create!(:name => 'Apple')
913
+ firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, '']
914
+ firm.save!
915
+
916
+ assert_equal 2, firm.clients(true).size
917
+ assert firm.clients.include?(companies(:second_client))
918
+ end
919
+
920
+ def test_get_ids_for_through
921
+ assert_equal [comments(:eager_other_comment1).id], authors(:mary).comment_ids
922
+ end
923
+
924
+ def test_modifying_a_through_a_has_many_should_raise
925
+ [
926
+ lambda { authors(:mary).comment_ids = [comments(:greetings).id, comments(:more_greetings).id] },
927
+ lambda { authors(:mary).comments = [comments(:greetings), comments(:more_greetings)] },
928
+ lambda { authors(:mary).comments << Comment.create!(:body => "Yay", :post_id => 424242) },
929
+ lambda { authors(:mary).comments.delete(authors(:mary).comments.first) },
930
+ ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
931
+ end
932
+
933
+ def test_dynamic_find_should_respect_association_order_for_through
934
+ assert_equal Comment.find(10), authors(:david).comments_desc.find(:first, :conditions => "comments.type = 'SpecialComment'")
935
+ assert_equal Comment.find(10), authors(:david).comments_desc.find_by_type('SpecialComment')
936
+ end
937
+
938
+ def test_dynamic_find_order_should_override_association_order_for_through
939
+ assert_equal Comment.find(3), authors(:david).comments_desc.find(:first, :conditions => "comments.type = 'SpecialComment'", :order => 'comments.id')
940
+ assert_equal Comment.find(3), authors(:david).comments_desc.find_by_type('SpecialComment', :order => 'comments.id')
941
+ end
942
+
943
+ def test_dynamic_find_all_should_respect_association_order_for_through
944
+ assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.find(:all, :conditions => "comments.type = 'SpecialComment'")
945
+ assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.find_all_by_type('SpecialComment')
946
+ end
947
+
948
+ def test_dynamic_find_all_order_should_override_association_order_for_through
949
+ assert_equal [Comment.find(3), Comment.find(6), Comment.find(7), Comment.find(10)], authors(:david).comments_desc.find(:all, :conditions => "comments.type = 'SpecialComment'", :order => 'comments.id')
950
+ assert_equal [Comment.find(3), Comment.find(6), Comment.find(7), Comment.find(10)], authors(:david).comments_desc.find_all_by_type('SpecialComment', :order => 'comments.id')
951
+ end
952
+
953
+ def test_dynamic_find_all_should_respect_association_limit_for_through
954
+ assert_equal 1, authors(:david).limited_comments.find(:all, :conditions => "comments.type = 'SpecialComment'").length
955
+ assert_equal 1, authors(:david).limited_comments.find_all_by_type('SpecialComment').length
956
+ end
957
+
958
+ def test_dynamic_find_all_order_should_override_association_limit_for_through
959
+ assert_equal 4, authors(:david).limited_comments.find(:all, :conditions => "comments.type = 'SpecialComment'", :limit => 9_000).length
960
+ assert_equal 4, authors(:david).limited_comments.find_all_by_type('SpecialComment', :limit => 9_000).length
961
+ end
962
+
963
+ def test_find_all_include_over_the_same_table_for_through
964
+ assert_equal 2, people(:michael).posts.find(:all, :include => :people).length
965
+ end
966
+
967
+ def test_has_many_through_respects_hash_conditions
968
+ assert_equal authors(:david).hello_posts, authors(:david).hello_posts_with_hash_conditions
969
+ assert_equal authors(:david).hello_post_comments, authors(:david).hello_post_comments_with_hash_conditions
970
+ end
971
+
972
+ def test_include_uses_array_include_after_loaded
973
+ firm = companies(:first_firm)
974
+ firm.clients.class # force load target
975
+
976
+ client = firm.clients.first
977
+
978
+ assert_no_queries do
979
+ assert firm.clients.loaded?
980
+ assert firm.clients.include?(client)
981
+ end
982
+ end
983
+
984
+ def test_include_checks_if_record_exists_if_target_not_loaded
985
+ firm = companies(:first_firm)
986
+ client = firm.clients.first
987
+
988
+ firm.reload
989
+ assert ! firm.clients.loaded?
990
+ assert_queries(1) do
991
+ assert firm.clients.include?(client)
992
+ end
993
+ assert ! firm.clients.loaded?
994
+ end
995
+
996
+ def test_include_loads_collection_if_target_uses_finder_sql
997
+ firm = companies(:first_firm)
998
+ client = firm.clients_using_sql.first
999
+
1000
+ firm.reload
1001
+ assert ! firm.clients_using_sql.loaded?
1002
+ assert firm.clients_using_sql.include?(client)
1003
+ assert firm.clients_using_sql.loaded?
1004
+ end
1005
+
1006
+
1007
+ def test_include_returns_false_for_non_matching_record_to_verify_scoping
1008
+ firm = companies(:first_firm)
1009
+ client = Client.create!(:name => 'Not Associated')
1010
+
1011
+ assert ! firm.clients.loaded?
1012
+ assert ! firm.clients.include?(client)
1013
+ end
1014
+
1015
+ def test_calling_first_or_last_on_association_should_not_load_association
1016
+ firm = companies(:first_firm)
1017
+ firm.clients.first
1018
+ firm.clients.last
1019
+ assert !firm.clients.loaded?
1020
+ end
1021
+
1022
+ def test_calling_first_or_last_on_loaded_association_should_not_fetch_with_query
1023
+ firm = companies(:first_firm)
1024
+ firm.clients.class # force load target
1025
+ assert firm.clients.loaded?
1026
+
1027
+ assert_no_queries do
1028
+ firm.clients.first
1029
+ assert_equal 2, firm.clients.first(2).size
1030
+ firm.clients.last
1031
+ assert_equal 2, firm.clients.last(2).size
1032
+ end
1033
+ end
1034
+
1035
+ def test_calling_first_or_last_on_existing_record_with_build_should_load_association
1036
+ firm = companies(:first_firm)
1037
+ firm.clients.build(:name => 'Foo')
1038
+ assert !firm.clients.loaded?
1039
+
1040
+ assert_queries 1 do
1041
+ firm.clients.first
1042
+ firm.clients.last
1043
+ end
1044
+
1045
+ assert firm.clients.loaded?
1046
+ end
1047
+
1048
+ def test_calling_first_or_last_on_existing_record_with_create_should_not_load_association
1049
+ firm = companies(:first_firm)
1050
+ firm.clients.create(:name => 'Foo')
1051
+ assert !firm.clients.loaded?
1052
+
1053
+ assert_queries 2 do
1054
+ firm.clients.first
1055
+ firm.clients.last
1056
+ end
1057
+
1058
+ assert !firm.clients.loaded?
1059
+ end
1060
+
1061
+ def test_calling_first_or_last_on_new_record_should_not_run_queries
1062
+ firm = Firm.new
1063
+
1064
+ assert_no_queries do
1065
+ firm.clients.first
1066
+ firm.clients.last
1067
+ end
1068
+ end
1069
+
1070
+ def test_calling_first_or_last_with_find_options_on_loaded_association_should_fetch_with_query
1071
+ firm = companies(:first_firm)
1072
+ firm.clients.class # force load target
1073
+
1074
+ assert_queries 2 do
1075
+ assert firm.clients.loaded?
1076
+ firm.clients.first(:order => 'name')
1077
+ firm.clients.last(:order => 'name')
1078
+ end
1079
+ end
1080
+
1081
+ def test_calling_first_or_last_with_integer_on_association_should_load_association
1082
+ firm = companies(:first_firm)
1083
+
1084
+ assert_queries 1 do
1085
+ firm.clients.first(2)
1086
+ firm.clients.last(2)
1087
+ end
1088
+
1089
+ assert firm.clients.loaded?
1090
+ end
1091
+
1092
+ def test_joins_with_namespaced_model_should_use_correct_type
1093
+ old = ActiveRecord::Base.store_full_sti_class
1094
+ ActiveRecord::Base.store_full_sti_class = true
1095
+
1096
+ firm = Namespaced::Firm.create({ :name => 'Some Company' })
1097
+ firm.clients.create({ :name => 'Some Client' })
1098
+
1099
+ stats = Namespaced::Firm.find(firm.id, {
1100
+ :select => "#{Namespaced::Firm.table_name}.id, COUNT(#{Namespaced::Client.table_name}.id) AS num_clients",
1101
+ :joins => :clients,
1102
+ :group => "#{Namespaced::Firm.table_name}.id"
1103
+ })
1104
+ assert_equal 1, stats.num_clients.to_i
1105
+
1106
+ ensure
1107
+ ActiveRecord::Base.store_full_sti_class = old
1108
+ end
1109
+
1110
+ def test_association_proxy_transaction_method_starts_transaction_in_association_class
1111
+ Comment.expects(:transaction)
1112
+ Post.find(:first).comments.transaction do
1113
+ # nothing
1114
+ end
1115
+ end
1116
+
1117
+ def test_sending_new_to_association_proxy_should_have_same_effect_as_calling_new
1118
+ client_association = companies(:first_firm).clients
1119
+ assert_equal client_association.new.attributes, client_association.send(:new).attributes
1120
+ end
1121
+
1122
+ def test_respond_to_private_class_methods
1123
+ client_association = companies(:first_firm).clients
1124
+ assert !client_association.respond_to?(:private_method)
1125
+ assert client_association.respond_to?(:private_method, true)
1126
+ end
1127
+
1128
+ def test_creating_using_primary_key
1129
+ firm = Firm.find(:first)
1130
+ client = firm.clients_using_primary_key.create!(:name => 'test')
1131
+ assert_equal firm.name, client.firm_name
1132
+ end
1133
+ end
1134
+