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,425 @@
1
+ require "cases/helper"
2
+ require 'models/developer'
3
+ require 'models/project'
4
+ require 'models/company'
5
+ require 'models/topic'
6
+ require 'models/reply'
7
+ require 'models/computer'
8
+ require 'models/customer'
9
+ require 'models/order'
10
+ require 'models/post'
11
+ require 'models/author'
12
+ require 'models/tag'
13
+ require 'models/tagging'
14
+ require 'models/comment'
15
+ require 'models/sponsor'
16
+ require 'models/member'
17
+ require 'models/essay'
18
+
19
+ class BelongsToAssociationsTest < ActiveRecord::TestCase
20
+ fixtures :accounts, :companies, :developers, :projects, :topics,
21
+ :developers_projects, :computers, :authors, :posts, :tags, :taggings, :comments
22
+
23
+ def test_belongs_to
24
+ Client.find(3).firm.name
25
+ assert_equal companies(:first_firm).name, Client.find(3).firm.name
26
+ assert !Client.find(3).firm.nil?, "Microsoft should have a firm"
27
+ end
28
+
29
+ def test_belongs_to_with_primary_key
30
+ client = Client.create(:name => "Primary key client", :firm_name => companies(:first_firm).name)
31
+ assert_equal companies(:first_firm).name, client.firm_with_primary_key.name
32
+ end
33
+
34
+ def test_proxy_assignment
35
+ account = Account.find(1)
36
+ assert_nothing_raised { account.firm = account.firm }
37
+ end
38
+
39
+ def test_triple_equality
40
+ assert Client.find(3).firm === Firm
41
+ assert Firm === Client.find(3).firm
42
+ end
43
+
44
+ def test_type_mismatch
45
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = 1 }
46
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) }
47
+ end
48
+
49
+ def test_natural_assignment
50
+ apple = Firm.create("name" => "Apple")
51
+ citibank = Account.create("credit_limit" => 10)
52
+ citibank.firm = apple
53
+ assert_equal apple.id, citibank.firm_id
54
+ end
55
+
56
+ def test_natural_assignment_with_primary_key
57
+ apple = Firm.create("name" => "Apple")
58
+ citibank = Client.create("name" => "Primary key client")
59
+ citibank.firm_with_primary_key = apple
60
+ assert_equal apple.name, citibank.firm_name
61
+ end
62
+
63
+ def test_no_unexpected_aliasing
64
+ first_firm = companies(:first_firm)
65
+ another_firm = companies(:another_firm)
66
+
67
+ citibank = Account.create("credit_limit" => 10)
68
+ citibank.firm = first_firm
69
+ original_proxy = citibank.firm
70
+ citibank.firm = another_firm
71
+
72
+ assert_equal first_firm.object_id, original_proxy.target.object_id
73
+ assert_equal another_firm.object_id, citibank.firm.target.object_id
74
+ end
75
+
76
+ def test_creating_the_belonging_object
77
+ citibank = Account.create("credit_limit" => 10)
78
+ apple = citibank.create_firm("name" => "Apple")
79
+ assert_equal apple, citibank.firm
80
+ citibank.save
81
+ citibank.reload
82
+ assert_equal apple, citibank.firm
83
+ end
84
+
85
+ def test_creating_the_belonging_object_with_primary_key
86
+ client = Client.create(:name => "Primary key client")
87
+ apple = client.create_firm_with_primary_key("name" => "Apple")
88
+ assert_equal apple, client.firm_with_primary_key
89
+ client.save
90
+ client.reload
91
+ assert_equal apple, client.firm_with_primary_key
92
+ end
93
+
94
+ def test_building_the_belonging_object
95
+ citibank = Account.create("credit_limit" => 10)
96
+ apple = citibank.build_firm("name" => "Apple")
97
+ citibank.save
98
+ assert_equal apple.id, citibank.firm_id
99
+ end
100
+
101
+ def test_building_the_belonging_object_with_primary_key
102
+ client = Client.create(:name => "Primary key client")
103
+ apple = client.build_firm_with_primary_key("name" => "Apple")
104
+ client.save
105
+ assert_equal apple.name, client.firm_name
106
+ end
107
+
108
+ def test_natural_assignment_to_nil
109
+ client = Client.find(3)
110
+ client.firm = nil
111
+ client.save
112
+ assert_nil client.firm(true)
113
+ assert_nil client.client_of
114
+ end
115
+
116
+ def test_natural_assignment_to_nil_with_primary_key
117
+ client = Client.create(:name => "Primary key client", :firm_name => companies(:first_firm).name)
118
+ client.firm_with_primary_key = nil
119
+ client.save
120
+ assert_nil client.firm_with_primary_key(true)
121
+ assert_nil client.client_of
122
+ end
123
+
124
+ def test_with_different_class_name
125
+ assert_equal Company.find(1).name, Company.find(3).firm_with_other_name.name
126
+ assert_not_nil Company.find(3).firm_with_other_name, "Microsoft should have a firm"
127
+ end
128
+
129
+ def test_with_condition
130
+ assert_equal Company.find(1).name, Company.find(3).firm_with_condition.name
131
+ assert_not_nil Company.find(3).firm_with_condition, "Microsoft should have a firm"
132
+ end
133
+
134
+ def test_with_select
135
+ assert_equal Company.find(2).firm_with_select.attributes.size, 1
136
+ assert_equal Company.find(2, :include => :firm_with_select ).firm_with_select.attributes.size, 1
137
+ end
138
+
139
+ def test_belongs_to_counter
140
+ debate = Topic.create("title" => "debate")
141
+ assert_equal 0, debate.send(:read_attribute, "replies_count"), "No replies yet"
142
+
143
+ trash = debate.replies.create("title" => "blah!", "content" => "world around!")
144
+ assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply created"
145
+
146
+ trash.destroy
147
+ assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted"
148
+ end
149
+
150
+ def test_belongs_to_with_primary_key_counter
151
+ debate = Topic.create("title" => "debate")
152
+ assert_equal 0, debate.send(:read_attribute, "replies_count"), "No replies yet"
153
+
154
+ trash = debate.replies_with_primary_key.create("title" => "blah!", "content" => "world around!")
155
+ assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply created"
156
+
157
+ trash.destroy
158
+ assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted"
159
+ end
160
+
161
+ def test_belongs_to_counter_with_assigning_nil
162
+ p = Post.find(1)
163
+ c = Comment.find(1)
164
+
165
+ assert_equal p.id, c.post_id
166
+ assert_equal 2, Post.find(p.id).comments.size
167
+
168
+ c.post = nil
169
+
170
+ assert_equal 1, Post.find(p.id).comments.size
171
+ end
172
+
173
+ def test_belongs_to_with_primary_key_counter_with_assigning_nil
174
+ debate = Topic.create("title" => "debate")
175
+ reply = Reply.create("title" => "blah!", "content" => "world around!", "parent_title" => "debate")
176
+
177
+ assert_equal debate.title, reply.parent_title
178
+ assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count")
179
+
180
+ reply.topic_with_primary_key = nil
181
+
182
+ assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count")
183
+ end
184
+
185
+ def test_belongs_to_counter_with_reassigning
186
+ t1 = Topic.create("title" => "t1")
187
+ t2 = Topic.create("title" => "t2")
188
+ r1 = Reply.new("title" => "r1", "content" => "r1")
189
+ r1.topic = t1
190
+
191
+ assert r1.save
192
+ assert_equal 1, Topic.find(t1.id).replies.size
193
+ assert_equal 0, Topic.find(t2.id).replies.size
194
+
195
+ r1.topic = Topic.find(t2.id)
196
+
197
+ assert r1.save
198
+ assert_equal 0, Topic.find(t1.id).replies.size
199
+ assert_equal 1, Topic.find(t2.id).replies.size
200
+
201
+ r1.topic = nil
202
+
203
+ assert_equal 0, Topic.find(t1.id).replies.size
204
+ assert_equal 0, Topic.find(t2.id).replies.size
205
+
206
+ r1.topic = t1
207
+
208
+ assert_equal 1, Topic.find(t1.id).replies.size
209
+ assert_equal 0, Topic.find(t2.id).replies.size
210
+
211
+ r1.destroy
212
+
213
+ assert_equal 0, Topic.find(t1.id).replies.size
214
+ assert_equal 0, Topic.find(t2.id).replies.size
215
+ end
216
+
217
+ def test_belongs_to_reassign_with_namespaced_models_and_counters
218
+ t1 = Web::Topic.create("title" => "t1")
219
+ t2 = Web::Topic.create("title" => "t2")
220
+ r1 = Web::Reply.new("title" => "r1", "content" => "r1")
221
+ r1.topic = t1
222
+
223
+ assert r1.save
224
+ assert_equal 1, Web::Topic.find(t1.id).replies.size
225
+ assert_equal 0, Web::Topic.find(t2.id).replies.size
226
+
227
+ r1.topic = Web::Topic.find(t2.id)
228
+
229
+ assert r1.save
230
+ assert_equal 0, Web::Topic.find(t1.id).replies.size
231
+ assert_equal 1, Web::Topic.find(t2.id).replies.size
232
+ end
233
+
234
+ def test_belongs_to_counter_after_save
235
+ topic = Topic.create!(:title => "monday night")
236
+ topic.replies.create!(:title => "re: monday night", :content => "football")
237
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
238
+
239
+ topic.save!
240
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
241
+ end
242
+
243
+ def test_belongs_to_counter_after_update_attributes
244
+ topic = Topic.create!(:title => "37s")
245
+ topic.replies.create!(:title => "re: 37s", :content => "rails")
246
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
247
+
248
+ topic.update_attributes(:title => "37signals")
249
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
250
+ end
251
+
252
+ def test_assignment_before_child_saved
253
+ final_cut = Client.new("name" => "Final Cut")
254
+ firm = Firm.find(1)
255
+ final_cut.firm = firm
256
+ assert final_cut.new_record?
257
+ assert final_cut.save
258
+ assert !final_cut.new_record?
259
+ assert !firm.new_record?
260
+ assert_equal firm, final_cut.firm
261
+ assert_equal firm, final_cut.firm(true)
262
+ end
263
+
264
+ def test_assignment_before_child_saved_with_primary_key
265
+ final_cut = Client.new("name" => "Final Cut")
266
+ firm = Firm.find(1)
267
+ final_cut.firm_with_primary_key = firm
268
+ assert final_cut.new_record?
269
+ assert final_cut.save
270
+ assert !final_cut.new_record?
271
+ assert !firm.new_record?
272
+ assert_equal firm, final_cut.firm_with_primary_key
273
+ assert_equal firm, final_cut.firm_with_primary_key(true)
274
+ end
275
+
276
+ def test_new_record_with_foreign_key_but_no_object
277
+ c = Client.new("firm_id" => 1)
278
+ assert_equal Firm.find(:first), c.firm_with_basic_id
279
+ end
280
+
281
+ def test_forgetting_the_load_when_foreign_key_enters_late
282
+ c = Client.new
283
+ assert_nil c.firm_with_basic_id
284
+
285
+ c.firm_id = 1
286
+ assert_equal Firm.find(:first), c.firm_with_basic_id
287
+ end
288
+
289
+ def test_field_name_same_as_foreign_key
290
+ computer = Computer.find(1)
291
+ assert_not_nil computer.developer, ":foreign key == attribute didn't lock up" # '
292
+ end
293
+
294
+ def test_counter_cache
295
+ topic = Topic.create :title => "Zoom-zoom-zoom"
296
+ assert_equal 0, topic[:replies_count]
297
+
298
+ reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
299
+ reply.topic = topic
300
+
301
+ assert_equal 1, topic.reload[:replies_count]
302
+ assert_equal 1, topic.replies.size
303
+
304
+ topic[:replies_count] = 15
305
+ assert_equal 15, topic.replies.size
306
+ end
307
+
308
+ def test_custom_counter_cache
309
+ reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
310
+ assert_equal 0, reply[:replies_count]
311
+
312
+ silly = SillyReply.create(:title => "gaga", :content => "boo-boo")
313
+ silly.reply = reply
314
+
315
+ assert_equal 1, reply.reload[:replies_count]
316
+ assert_equal 1, reply.replies.size
317
+
318
+ reply[:replies_count] = 17
319
+ assert_equal 17, reply.replies.size
320
+ end
321
+
322
+ def test_association_assignment_sticks
323
+ post = Post.find(:first)
324
+
325
+ author1, author2 = Author.find(:all, :limit => 2)
326
+ assert_not_nil author1
327
+ assert_not_nil author2
328
+
329
+ # make sure the association is loaded
330
+ post.author
331
+
332
+ # set the association by id, directly
333
+ post.author_id = author2.id
334
+
335
+ # save and reload
336
+ post.save!
337
+ post.reload
338
+
339
+ # the author id of the post should be the id we set
340
+ assert_equal post.author_id, author2.id
341
+ end
342
+
343
+ def test_cant_save_readonly_association
344
+ assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_client).readonly_firm.save! }
345
+ assert companies(:first_client).readonly_firm.readonly?
346
+ end
347
+
348
+ def test_polymorphic_assignment_foreign_type_field_updating
349
+ # should update when assigning a saved record
350
+ sponsor = Sponsor.new
351
+ member = Member.create
352
+ sponsor.sponsorable = member
353
+ assert_equal "Member", sponsor.sponsorable_type
354
+
355
+ # should update when assigning a new record
356
+ sponsor = Sponsor.new
357
+ member = Member.new
358
+ sponsor.sponsorable = member
359
+ assert_equal "Member", sponsor.sponsorable_type
360
+ end
361
+
362
+ def test_polymorphic_assignment_with_primary_key_foreign_type_field_updating
363
+ # should update when assigning a saved record
364
+ essay = Essay.new
365
+ writer = Author.create(:name => "David")
366
+ essay.writer = writer
367
+ assert_equal "Author", essay.writer_type
368
+
369
+ # should update when assigning a new record
370
+ essay = Essay.new
371
+ writer = Author.new
372
+ essay.writer = writer
373
+ assert_equal "Author", essay.writer_type
374
+ end
375
+
376
+ def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records
377
+ sponsor = Sponsor.new
378
+ saved_member = Member.create
379
+ new_member = Member.new
380
+
381
+ sponsor.sponsorable = saved_member
382
+ assert_equal saved_member.id, sponsor.sponsorable_id
383
+
384
+ sponsor.sponsorable = new_member
385
+ assert_equal nil, sponsor.sponsorable_id
386
+ end
387
+
388
+ def test_polymorphic_assignment_with_primary_key_updates_foreign_id_field_for_new_and_saved_records
389
+ essay = Essay.new
390
+ saved_writer = Author.create(:name => "David")
391
+ new_writer = Author.new
392
+
393
+ essay.writer = saved_writer
394
+ assert_equal saved_writer.name, essay.writer_id
395
+
396
+ essay.writer = new_writer
397
+ assert_equal nil, essay.writer_id
398
+ end
399
+
400
+ def test_belongs_to_proxy_should_not_respond_to_private_methods
401
+ assert_raise(NoMethodError) { companies(:first_firm).private_method }
402
+ assert_raise(NoMethodError) { companies(:second_client).firm.private_method }
403
+ end
404
+
405
+ def test_belongs_to_proxy_should_respond_to_private_methods_via_send
406
+ companies(:first_firm).send(:private_method)
407
+ companies(:second_client).firm.send(:private_method)
408
+ end
409
+
410
+ def test_save_of_record_with_loaded_belongs_to
411
+ @account = companies(:first_firm).account
412
+
413
+ assert_nothing_raised do
414
+ Account.find(@account.id).save!
415
+ Account.find(@account.id, :include => :firm).save!
416
+ end
417
+
418
+ @account.firm.delete
419
+
420
+ assert_nothing_raised do
421
+ Account.find(@account.id).save!
422
+ Account.find(@account.id, :include => :firm).save!
423
+ end
424
+ end
425
+ end
@@ -0,0 +1,161 @@
1
+ require "cases/helper"
2
+ require 'models/post'
3
+ require 'models/comment'
4
+ require 'models/author'
5
+ require 'models/category'
6
+ require 'models/project'
7
+ require 'models/developer'
8
+
9
+ class AssociationCallbacksTest < ActiveRecord::TestCase
10
+ fixtures :posts, :authors, :projects, :developers
11
+
12
+ def setup
13
+ @david = authors(:david)
14
+ @thinking = posts(:thinking)
15
+ @authorless = posts(:authorless)
16
+ assert @david.post_log.empty?
17
+ end
18
+
19
+ def test_adding_macro_callbacks
20
+ @david.posts_with_callbacks << @thinking
21
+ assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}"], @david.post_log
22
+ @david.posts_with_callbacks << @thinking
23
+ assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}", "before_adding#{@thinking.id}",
24
+ "after_adding#{@thinking.id}"], @david.post_log
25
+ end
26
+
27
+ def test_adding_with_proc_callbacks
28
+ @david.posts_with_proc_callbacks << @thinking
29
+ assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}"], @david.post_log
30
+ @david.posts_with_proc_callbacks << @thinking
31
+ assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}", "before_adding#{@thinking.id}",
32
+ "after_adding#{@thinking.id}"], @david.post_log
33
+ end
34
+
35
+ def test_removing_with_macro_callbacks
36
+ first_post, second_post = @david.posts_with_callbacks[0, 2]
37
+ @david.posts_with_callbacks.delete(first_post)
38
+ assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}"], @david.post_log
39
+ @david.posts_with_callbacks.delete(second_post)
40
+ assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}", "before_removing#{second_post.id}",
41
+ "after_removing#{second_post.id}"], @david.post_log
42
+ end
43
+
44
+ def test_removing_with_proc_callbacks
45
+ first_post, second_post = @david.posts_with_callbacks[0, 2]
46
+ @david.posts_with_proc_callbacks.delete(first_post)
47
+ assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}"], @david.post_log
48
+ @david.posts_with_proc_callbacks.delete(second_post)
49
+ assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}", "before_removing#{second_post.id}",
50
+ "after_removing#{second_post.id}"], @david.post_log
51
+ end
52
+
53
+ def test_multiple_callbacks
54
+ @david.posts_with_multiple_callbacks << @thinking
55
+ assert_equal ["before_adding#{@thinking.id}", "before_adding_proc#{@thinking.id}", "after_adding#{@thinking.id}",
56
+ "after_adding_proc#{@thinking.id}"], @david.post_log
57
+ @david.posts_with_multiple_callbacks << @thinking
58
+ assert_equal ["before_adding#{@thinking.id}", "before_adding_proc#{@thinking.id}", "after_adding#{@thinking.id}",
59
+ "after_adding_proc#{@thinking.id}", "before_adding#{@thinking.id}", "before_adding_proc#{@thinking.id}",
60
+ "after_adding#{@thinking.id}", "after_adding_proc#{@thinking.id}"], @david.post_log
61
+ end
62
+
63
+ def test_has_many_callbacks_with_create
64
+ morten = Author.create :name => "Morten"
65
+ post = morten.posts_with_proc_callbacks.create! :title => "Hello", :body => "How are you doing?"
66
+ assert_equal ["before_adding<new>", "after_adding#{post.id}"], morten.post_log
67
+ end
68
+
69
+ def test_has_many_callbacks_with_create!
70
+ morten = Author.create! :name => "Morten"
71
+ post = morten.posts_with_proc_callbacks.create :title => "Hello", :body => "How are you doing?"
72
+ assert_equal ["before_adding<new>", "after_adding#{post.id}"], morten.post_log
73
+ end
74
+
75
+ def test_has_many_callbacks_for_save_on_parent
76
+ jack = Author.new :name => "Jack"
77
+ post = jack.posts_with_callbacks.build :title => "Call me back!", :body => "Before you wake up and after you sleep"
78
+
79
+ callback_log = ["before_adding<new>", "after_adding#{jack.posts_with_callbacks.first.id}"]
80
+ assert_equal callback_log, jack.post_log
81
+ assert jack.save
82
+ assert_equal 1, jack.posts_with_callbacks.count
83
+ assert_equal callback_log, jack.post_log
84
+ end
85
+
86
+ def test_has_and_belongs_to_many_add_callback
87
+ david = developers(:david)
88
+ ar = projects(:active_record)
89
+ assert ar.developers_log.empty?
90
+ ar.developers_with_callbacks << david
91
+ assert_equal ["before_adding#{david.id}", "after_adding#{david.id}"], ar.developers_log
92
+ ar.developers_with_callbacks << david
93
+ assert_equal ["before_adding#{david.id}", "after_adding#{david.id}", "before_adding#{david.id}",
94
+ "after_adding#{david.id}"], ar.developers_log
95
+ end
96
+
97
+ def test_has_and_belongs_to_many_after_add_called_after_save
98
+ ar = projects(:active_record)
99
+ assert ar.developers_log.empty?
100
+ alice = Developer.new(:name => 'alice')
101
+ ar.developers_with_callbacks << alice
102
+ assert_equal"after_adding#{alice.id}", ar.developers_log.last
103
+
104
+ bob = ar.developers_with_callbacks.create(:name => 'bob')
105
+ assert_equal "after_adding#{bob.id}", ar.developers_log.last
106
+
107
+ ar.developers_with_callbacks.build(:name => 'charlie')
108
+ assert_equal "after_adding<new>", ar.developers_log.last
109
+ end
110
+
111
+
112
+ def test_has_and_belongs_to_many_remove_callback
113
+ david = developers(:david)
114
+ jamis = developers(:jamis)
115
+ activerecord = projects(:active_record)
116
+ assert activerecord.developers_log.empty?
117
+ activerecord.developers_with_callbacks.delete(david)
118
+ assert_equal ["before_removing#{david.id}", "after_removing#{david.id}"], activerecord.developers_log
119
+
120
+ activerecord.developers_with_callbacks.delete(jamis)
121
+ assert_equal ["before_removing#{david.id}", "after_removing#{david.id}", "before_removing#{jamis.id}",
122
+ "after_removing#{jamis.id}"], activerecord.developers_log
123
+ end
124
+
125
+ def test_has_and_belongs_to_many_remove_callback_on_clear
126
+ activerecord = projects(:active_record)
127
+ assert activerecord.developers_log.empty?
128
+ if activerecord.developers_with_callbacks.size == 0
129
+ activerecord.developers << developers(:david)
130
+ activerecord.developers << developers(:jamis)
131
+ activerecord.reload
132
+ assert activerecord.developers_with_callbacks.size == 2
133
+ end
134
+ log_array = activerecord.developers_with_callbacks.collect {|d| ["before_removing#{d.id}","after_removing#{d.id}"]}.flatten.sort
135
+ assert activerecord.developers_with_callbacks.clear
136
+ assert_equal log_array, activerecord.developers_log.sort
137
+ end
138
+
139
+ def test_has_many_and_belongs_to_many_callbacks_for_save_on_parent
140
+ project = Project.new :name => "Callbacks"
141
+ project.developers_with_callbacks.build :name => "Jack", :salary => 95000
142
+
143
+ callback_log = ["before_adding<new>", "after_adding<new>"]
144
+ assert_equal callback_log, project.developers_log
145
+ assert project.save
146
+ assert_equal 1, project.developers_with_callbacks.size
147
+ assert_equal callback_log, project.developers_log
148
+ end
149
+
150
+ def test_dont_add_if_before_callback_raises_exception
151
+ assert !@david.unchangable_posts.include?(@authorless)
152
+ begin
153
+ @david.unchangable_posts << @authorless
154
+ rescue Exception => e
155
+ end
156
+ assert @david.post_log.empty?
157
+ assert !@david.unchangable_posts.include?(@authorless)
158
+ @david.reload
159
+ assert !@david.unchangable_posts.include?(@authorless)
160
+ end
161
+ end