activerecord 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (311) hide show
  1. data/CHANGELOG +4928 -3
  2. data/README +45 -46
  3. data/RUNNING_UNIT_TESTS +8 -11
  4. data/Rakefile +247 -0
  5. data/install.rb +8 -38
  6. data/lib/active_record/aggregations.rb +64 -49
  7. data/lib/active_record/associations/association_collection.rb +217 -47
  8. data/lib/active_record/associations/association_proxy.rb +159 -0
  9. data/lib/active_record/associations/belongs_to_association.rb +56 -0
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +155 -37
  12. data/lib/active_record/associations/has_many_association.rb +145 -75
  13. data/lib/active_record/associations/has_many_through_association.rb +283 -0
  14. data/lib/active_record/associations/has_one_association.rb +96 -0
  15. data/lib/active_record/associations.rb +1537 -304
  16. data/lib/active_record/attribute_methods.rb +328 -0
  17. data/lib/active_record/base.rb +2001 -588
  18. data/lib/active_record/calculations.rb +269 -0
  19. data/lib/active_record/callbacks.rb +169 -165
  20. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +308 -0
  21. data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -0
  22. data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
  23. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  24. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +472 -0
  25. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +306 -0
  26. data/lib/active_record/connection_adapters/abstract_adapter.rb +125 -279
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +442 -77
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +805 -135
  29. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  30. data/lib/active_record/connection_adapters/sqlite_adapter.rb +353 -69
  31. data/lib/active_record/fixtures.rb +946 -100
  32. data/lib/active_record/locking/optimistic.rb +144 -0
  33. data/lib/active_record/locking/pessimistic.rb +77 -0
  34. data/lib/active_record/migration.rb +417 -0
  35. data/lib/active_record/observer.rb +142 -32
  36. data/lib/active_record/query_cache.rb +23 -0
  37. data/lib/active_record/reflection.rb +163 -70
  38. data/lib/active_record/schema.rb +58 -0
  39. data/lib/active_record/schema_dumper.rb +171 -0
  40. data/lib/active_record/serialization.rb +98 -0
  41. data/lib/active_record/serializers/json_serializer.rb +71 -0
  42. data/lib/active_record/serializers/xml_serializer.rb +315 -0
  43. data/lib/active_record/timestamp.rb +41 -0
  44. data/lib/active_record/transactions.rb +87 -57
  45. data/lib/active_record/validations.rb +909 -122
  46. data/lib/active_record/vendor/db2.rb +362 -0
  47. data/lib/active_record/vendor/mysql.rb +126 -29
  48. data/lib/active_record/version.rb +9 -0
  49. data/lib/active_record.rb +35 -7
  50. data/lib/activerecord.rb +1 -0
  51. data/test/aaa_create_tables_test.rb +72 -0
  52. data/test/abstract_unit.rb +73 -5
  53. data/test/active_schema_test_mysql.rb +43 -0
  54. data/test/adapter_test.rb +105 -0
  55. data/test/adapter_test_sqlserver.rb +95 -0
  56. data/test/aggregations_test.rb +110 -16
  57. data/test/all.sh +2 -2
  58. data/test/ar_schema_test.rb +33 -0
  59. data/test/association_inheritance_reload.rb +14 -0
  60. data/test/associations/ar_joins_test.rb +0 -0
  61. data/test/associations/callbacks_test.rb +147 -0
  62. data/test/associations/cascaded_eager_loading_test.rb +110 -0
  63. data/test/associations/eager_singularization_test.rb +145 -0
  64. data/test/associations/eager_test.rb +442 -0
  65. data/test/associations/extension_test.rb +47 -0
  66. data/test/associations/inner_join_association_test.rb +88 -0
  67. data/test/associations/join_model_test.rb +553 -0
  68. data/test/associations_test.rb +1930 -267
  69. data/test/attribute_methods_test.rb +146 -0
  70. data/test/base_test.rb +1316 -84
  71. data/test/binary_test.rb +32 -0
  72. data/test/calculations_test.rb +251 -0
  73. data/test/callbacks_test.rb +400 -0
  74. data/test/class_inheritable_attributes_test.rb +3 -4
  75. data/test/column_alias_test.rb +17 -0
  76. data/test/connection_test_firebird.rb +8 -0
  77. data/test/connection_test_mysql.rb +30 -0
  78. data/test/connections/native_db2/connection.rb +25 -0
  79. data/test/connections/native_firebird/connection.rb +26 -0
  80. data/test/connections/native_frontbase/connection.rb +27 -0
  81. data/test/connections/native_mysql/connection.rb +21 -18
  82. data/test/connections/native_openbase/connection.rb +21 -0
  83. data/test/connections/native_oracle/connection.rb +27 -0
  84. data/test/connections/native_postgresql/connection.rb +17 -18
  85. data/test/connections/native_sqlite/connection.rb +17 -16
  86. data/test/connections/native_sqlite3/connection.rb +25 -0
  87. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  88. data/test/connections/native_sybase/connection.rb +23 -0
  89. data/test/copy_table_test_sqlite.rb +69 -0
  90. data/test/datatype_test_postgresql.rb +203 -0
  91. data/test/date_time_test.rb +37 -0
  92. data/test/default_test_firebird.rb +16 -0
  93. data/test/defaults_test.rb +67 -0
  94. data/test/deprecated_finder_test.rb +30 -0
  95. data/test/finder_test.rb +607 -32
  96. data/test/fixtures/accounts.yml +28 -0
  97. data/test/fixtures/all/developers.yml +0 -0
  98. data/test/fixtures/all/people.csv +0 -0
  99. data/test/fixtures/all/tasks.yml +0 -0
  100. data/test/fixtures/author.rb +107 -0
  101. data/test/fixtures/author_favorites.yml +4 -0
  102. data/test/fixtures/authors.yml +7 -0
  103. data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
  104. data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
  105. data/test/fixtures/bad_fixtures/blank_line +3 -0
  106. data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
  107. data/test/fixtures/bad_fixtures/missing_value +1 -0
  108. data/test/fixtures/binaries.yml +132 -0
  109. data/test/fixtures/binary.rb +2 -0
  110. data/test/fixtures/book.rb +4 -0
  111. data/test/fixtures/books.yml +7 -0
  112. data/test/fixtures/categories/special_categories.yml +9 -0
  113. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  114. data/test/fixtures/categories.yml +14 -0
  115. data/test/fixtures/categories_ordered.yml +7 -0
  116. data/test/fixtures/categories_posts.yml +23 -0
  117. data/test/fixtures/categorization.rb +5 -0
  118. data/test/fixtures/categorizations.yml +17 -0
  119. data/test/fixtures/category.rb +26 -0
  120. data/test/fixtures/citation.rb +6 -0
  121. data/test/fixtures/comment.rb +23 -0
  122. data/test/fixtures/comments.yml +59 -0
  123. data/test/fixtures/companies.yml +55 -0
  124. data/test/fixtures/company.rb +81 -4
  125. data/test/fixtures/company_in_module.rb +32 -6
  126. data/test/fixtures/computer.rb +4 -0
  127. data/test/fixtures/computers.yml +4 -0
  128. data/test/fixtures/contact.rb +16 -0
  129. data/test/fixtures/courses.yml +7 -0
  130. data/test/fixtures/customer.rb +28 -3
  131. data/test/fixtures/customers.yml +17 -0
  132. data/test/fixtures/db_definitions/db2.drop.sql +33 -0
  133. data/test/fixtures/db_definitions/db2.sql +235 -0
  134. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  135. data/test/fixtures/db_definitions/db22.sql +5 -0
  136. data/test/fixtures/db_definitions/firebird.drop.sql +65 -0
  137. data/test/fixtures/db_definitions/firebird.sql +310 -0
  138. data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
  139. data/test/fixtures/db_definitions/firebird2.sql +6 -0
  140. data/test/fixtures/db_definitions/frontbase.drop.sql +33 -0
  141. data/test/fixtures/db_definitions/frontbase.sql +273 -0
  142. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  143. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  144. data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
  145. data/test/fixtures/db_definitions/openbase.sql +318 -0
  146. data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
  147. data/test/fixtures/db_definitions/openbase2.sql +7 -0
  148. data/test/fixtures/db_definitions/oracle.drop.sql +67 -0
  149. data/test/fixtures/db_definitions/oracle.sql +330 -0
  150. data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
  151. data/test/fixtures/db_definitions/oracle2.sql +6 -0
  152. data/test/fixtures/db_definitions/postgresql.drop.sql +44 -0
  153. data/test/fixtures/db_definitions/postgresql.sql +217 -38
  154. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  155. data/test/fixtures/db_definitions/postgresql2.sql +2 -2
  156. data/test/fixtures/db_definitions/schema.rb +354 -0
  157. data/test/fixtures/db_definitions/schema2.rb +11 -0
  158. data/test/fixtures/db_definitions/sqlite.drop.sql +33 -0
  159. data/test/fixtures/db_definitions/sqlite.sql +139 -5
  160. data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
  161. data/test/fixtures/db_definitions/sqlite2.sql +1 -0
  162. data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
  163. data/test/fixtures/db_definitions/sybase.sql +222 -0
  164. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  165. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  166. data/test/fixtures/developer.rb +70 -6
  167. data/test/fixtures/developers.yml +21 -0
  168. data/test/fixtures/developers_projects/david_action_controller +2 -1
  169. data/test/fixtures/developers_projects/david_active_record +2 -1
  170. data/test/fixtures/developers_projects.yml +17 -0
  171. data/test/fixtures/edge.rb +5 -0
  172. data/test/fixtures/edges.yml +6 -0
  173. data/test/fixtures/entrants.yml +14 -0
  174. data/test/fixtures/example.log +1 -0
  175. data/test/fixtures/fk_test_has_fk.yml +3 -0
  176. data/test/fixtures/fk_test_has_pk.yml +2 -0
  177. data/test/fixtures/flowers.jpg +0 -0
  178. data/test/fixtures/funny_jokes.yml +10 -0
  179. data/test/fixtures/item.rb +7 -0
  180. data/test/fixtures/items.yml +4 -0
  181. data/test/fixtures/joke.rb +3 -0
  182. data/test/fixtures/keyboard.rb +3 -0
  183. data/test/fixtures/legacy_thing.rb +3 -0
  184. data/test/fixtures/legacy_things.yml +3 -0
  185. data/test/fixtures/matey.rb +4 -0
  186. data/test/fixtures/mateys.yml +4 -0
  187. data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
  188. data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
  189. data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
  190. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  191. data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
  192. data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
  193. data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
  194. data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
  195. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  196. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  197. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  198. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  199. data/test/fixtures/minimalistic.rb +2 -0
  200. data/test/fixtures/minimalistics.yml +2 -0
  201. data/test/fixtures/mixed_case_monkey.rb +3 -0
  202. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  203. data/test/fixtures/mixins.yml +29 -0
  204. data/test/fixtures/movies.yml +7 -0
  205. data/test/fixtures/naked/csv/accounts.csv +1 -0
  206. data/test/fixtures/naked/yml/accounts.yml +1 -0
  207. data/test/fixtures/naked/yml/companies.yml +1 -0
  208. data/test/fixtures/naked/yml/courses.yml +1 -0
  209. data/test/fixtures/order.rb +4 -0
  210. data/test/fixtures/parrot.rb +13 -0
  211. data/test/fixtures/parrots.yml +27 -0
  212. data/test/fixtures/parrots_pirates.yml +7 -0
  213. data/test/fixtures/people.yml +3 -0
  214. data/test/fixtures/person.rb +4 -0
  215. data/test/fixtures/pirate.rb +5 -0
  216. data/test/fixtures/pirates.yml +9 -0
  217. data/test/fixtures/post.rb +59 -0
  218. data/test/fixtures/posts.yml +48 -0
  219. data/test/fixtures/project.rb +27 -2
  220. data/test/fixtures/projects.yml +7 -0
  221. data/test/fixtures/reader.rb +4 -0
  222. data/test/fixtures/readers.yml +4 -0
  223. data/test/fixtures/reply.rb +18 -2
  224. data/test/fixtures/reserved_words/distinct.yml +5 -0
  225. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  226. data/test/fixtures/reserved_words/group.yml +14 -0
  227. data/test/fixtures/reserved_words/select.yml +8 -0
  228. data/test/fixtures/reserved_words/values.yml +7 -0
  229. data/test/fixtures/ship.rb +3 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/subject.rb +4 -0
  232. data/test/fixtures/subscriber.rb +4 -3
  233. data/test/fixtures/tag.rb +7 -0
  234. data/test/fixtures/tagging.rb +10 -0
  235. data/test/fixtures/taggings.yml +25 -0
  236. data/test/fixtures/tags.yml +7 -0
  237. data/test/fixtures/task.rb +3 -0
  238. data/test/fixtures/tasks.yml +7 -0
  239. data/test/fixtures/topic.rb +20 -3
  240. data/test/fixtures/topics.yml +22 -0
  241. data/test/fixtures/treasure.rb +4 -0
  242. data/test/fixtures/treasures.yml +10 -0
  243. data/test/fixtures/vertex.rb +9 -0
  244. data/test/fixtures/vertices.yml +4 -0
  245. data/test/fixtures_test.rb +574 -8
  246. data/test/inheritance_test.rb +113 -27
  247. data/test/json_serialization_test.rb +180 -0
  248. data/test/lifecycle_test.rb +56 -29
  249. data/test/locking_test.rb +273 -0
  250. data/test/method_scoping_test.rb +416 -0
  251. data/test/migration_test.rb +933 -0
  252. data/test/migration_test_firebird.rb +124 -0
  253. data/test/mixin_test.rb +95 -0
  254. data/test/modules_test.rb +23 -10
  255. data/test/multiple_db_test.rb +17 -3
  256. data/test/pk_test.rb +59 -15
  257. data/test/query_cache_test.rb +104 -0
  258. data/test/readonly_test.rb +107 -0
  259. data/test/reflection_test.rb +124 -27
  260. data/test/reserved_word_test_mysql.rb +177 -0
  261. data/test/schema_authorization_test_postgresql.rb +75 -0
  262. data/test/schema_dumper_test.rb +131 -0
  263. data/test/schema_test_postgresql.rb +64 -0
  264. data/test/serialization_test.rb +47 -0
  265. data/test/synonym_test_oracle.rb +17 -0
  266. data/test/table_name_test_sqlserver.rb +23 -0
  267. data/test/threaded_connections_test.rb +48 -0
  268. data/test/transactions_test.rb +227 -29
  269. data/test/unconnected_test.rb +14 -6
  270. data/test/validations_test.rb +1293 -32
  271. data/test/xml_serialization_test.rb +202 -0
  272. metadata +347 -143
  273. data/dev-utils/eval_debugger.rb +0 -9
  274. data/examples/associations.rb +0 -87
  275. data/examples/shared_setup.rb +0 -15
  276. data/examples/validation.rb +0 -88
  277. data/lib/active_record/deprecated_associations.rb +0 -70
  278. data/lib/active_record/support/class_attribute_accessors.rb +0 -43
  279. data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
  280. data/lib/active_record/support/clean_logger.rb +0 -10
  281. data/lib/active_record/support/inflector.rb +0 -70
  282. data/lib/active_record/vendor/simple.rb +0 -702
  283. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  284. data/lib/active_record/wrappings.rb +0 -59
  285. data/rakefile +0 -122
  286. data/test/deprecated_associations_test.rb +0 -336
  287. data/test/fixtures/accounts/signals37 +0 -3
  288. data/test/fixtures/accounts/unknown +0 -2
  289. data/test/fixtures/companies/first_client +0 -6
  290. data/test/fixtures/companies/first_firm +0 -4
  291. data/test/fixtures/companies/second_client +0 -6
  292. data/test/fixtures/courses/java +0 -2
  293. data/test/fixtures/courses/ruby +0 -2
  294. data/test/fixtures/customers/david +0 -6
  295. data/test/fixtures/db_definitions/mysql.sql +0 -96
  296. data/test/fixtures/db_definitions/mysql2.sql +0 -4
  297. data/test/fixtures/developers/david +0 -2
  298. data/test/fixtures/developers/jamis +0 -2
  299. data/test/fixtures/entrants/first +0 -3
  300. data/test/fixtures/entrants/second +0 -3
  301. data/test/fixtures/entrants/third +0 -3
  302. data/test/fixtures/fixture_database.sqlite +0 -0
  303. data/test/fixtures/fixture_database_2.sqlite +0 -0
  304. data/test/fixtures/movies/first +0 -2
  305. data/test/fixtures/movies/second +0 -2
  306. data/test/fixtures/projects/action_controller +0 -2
  307. data/test/fixtures/projects/active_record +0 -2
  308. data/test/fixtures/topics/first +0 -9
  309. data/test/fixtures/topics/second +0 -8
  310. data/test/inflector_test.rb +0 -104
  311. data/test/thread_safety_test.rb +0 -33
@@ -0,0 +1,553 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/tag'
3
+ require 'fixtures/tagging'
4
+ require 'fixtures/post'
5
+ require 'fixtures/item'
6
+ require 'fixtures/comment'
7
+ require 'fixtures/author'
8
+ require 'fixtures/category'
9
+ require 'fixtures/categorization'
10
+ require 'fixtures/vertex'
11
+ require 'fixtures/edge'
12
+ require 'fixtures/book'
13
+ require 'fixtures/citation'
14
+
15
+ class AssociationsJoinModelTest < Test::Unit::TestCase
16
+ self.use_transactional_fixtures = false
17
+ fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books
18
+
19
+ def test_has_many
20
+ assert authors(:david).categories.include?(categories(:general))
21
+ end
22
+
23
+ def test_has_many_inherited
24
+ assert authors(:mary).categories.include?(categories(:sti_test))
25
+ end
26
+
27
+ def test_inherited_has_many
28
+ assert categories(:sti_test).authors.include?(authors(:mary))
29
+ end
30
+
31
+ def test_has_many_uniq_through_join_model
32
+ assert_equal 2, authors(:mary).categorized_posts.size
33
+ assert_equal 1, authors(:mary).unique_categorized_posts.size
34
+ end
35
+
36
+ def test_has_many_uniq_through_count
37
+ author = authors(:mary)
38
+ assert !authors(:mary).unique_categorized_posts.loaded?
39
+ assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count }
40
+ assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title) }
41
+ assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, :conditions => "title is NULL") }
42
+ assert !authors(:mary).unique_categorized_posts.loaded?
43
+ end
44
+
45
+ def test_polymorphic_has_many
46
+ assert posts(:welcome).taggings.include?(taggings(:welcome_general))
47
+ end
48
+
49
+ def test_polymorphic_has_one
50
+ assert_equal taggings(:welcome_general), posts(:welcome).tagging
51
+ end
52
+
53
+ def test_polymorphic_belongs_to
54
+ assert_equal posts(:welcome), posts(:welcome).taggings.first.taggable
55
+ end
56
+
57
+ def test_polymorphic_has_many_going_through_join_model
58
+ assert_equal tags(:general), tag = posts(:welcome).tags.first
59
+ assert_no_queries do
60
+ tag.tagging
61
+ end
62
+ end
63
+
64
+ def test_count_polymorphic_has_many
65
+ assert_equal 1, posts(:welcome).taggings.count
66
+ assert_equal 1, posts(:welcome).tags.count
67
+ end
68
+
69
+ def test_polymorphic_has_many_going_through_join_model_with_find
70
+ assert_equal tags(:general), tag = posts(:welcome).tags.find(:first)
71
+ assert_no_queries do
72
+ tag.tagging
73
+ end
74
+ end
75
+
76
+ def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection
77
+ assert_equal tags(:general), tag = posts(:welcome).funky_tags.first
78
+ assert_no_queries do
79
+ tag.tagging
80
+ end
81
+ end
82
+
83
+ def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection_with_find
84
+ assert_equal tags(:general), tag = posts(:welcome).funky_tags.find(:first)
85
+ assert_no_queries do
86
+ tag.tagging
87
+ end
88
+ end
89
+
90
+ def test_polymorphic_has_many_going_through_join_model_with_disabled_include
91
+ assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
92
+ assert_queries 1 do
93
+ tag.tagging
94
+ end
95
+ end
96
+
97
+ def test_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins
98
+ assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
99
+ tag.author_id
100
+ end
101
+
102
+ def test_polymorphic_has_many_going_through_join_model_with_custom_foreign_key
103
+ assert_equal tags(:misc), taggings(:welcome_general).super_tag
104
+ assert_equal tags(:misc), posts(:welcome).super_tags.first
105
+ end
106
+
107
+ def test_polymorphic_has_many_create_model_with_inheritance_and_custom_base_class
108
+ post = SubStiPost.create :title => 'SubStiPost', :body => 'SubStiPost body'
109
+ assert_instance_of SubStiPost, post
110
+
111
+ tagging = tags(:misc).taggings.create(:taggable => post)
112
+ assert_equal "SubStiPost", tagging.taggable_type
113
+ end
114
+
115
+ def test_polymorphic_has_many_going_through_join_model_with_inheritance
116
+ assert_equal tags(:general), posts(:thinking).tags.first
117
+ end
118
+
119
+ def test_polymorphic_has_many_going_through_join_model_with_inheritance_with_custom_class_name
120
+ assert_equal tags(:general), posts(:thinking).funky_tags.first
121
+ end
122
+
123
+ def test_polymorphic_has_many_create_model_with_inheritance
124
+ post = posts(:thinking)
125
+ assert_instance_of SpecialPost, post
126
+
127
+ tagging = tags(:misc).taggings.create(:taggable => post)
128
+ assert_equal "Post", tagging.taggable_type
129
+ end
130
+
131
+ def test_polymorphic_has_one_create_model_with_inheritance
132
+ tagging = tags(:misc).create_tagging(:taggable => posts(:thinking))
133
+ assert_equal "Post", tagging.taggable_type
134
+ end
135
+
136
+ def test_set_polymorphic_has_many
137
+ tagging = tags(:misc).taggings.create
138
+ posts(:thinking).taggings << tagging
139
+ assert_equal "Post", tagging.taggable_type
140
+ end
141
+
142
+ def test_set_polymorphic_has_one
143
+ tagging = tags(:misc).taggings.create
144
+ posts(:thinking).tagging = tagging
145
+ assert_equal "Post", tagging.taggable_type
146
+ end
147
+
148
+ def test_create_polymorphic_has_many_with_scope
149
+ old_count = posts(:welcome).taggings.count
150
+ tagging = posts(:welcome).taggings.create(:tag => tags(:misc))
151
+ assert_equal "Post", tagging.taggable_type
152
+ assert_equal old_count+1, posts(:welcome).taggings.count
153
+ end
154
+
155
+ def test_create_bang_polymorphic_with_has_many_scope
156
+ old_count = posts(:welcome).taggings.count
157
+ tagging = posts(:welcome).taggings.create!(:tag => tags(:misc))
158
+ assert_equal "Post", tagging.taggable_type
159
+ assert_equal old_count+1, posts(:welcome).taggings.count
160
+ end
161
+
162
+ def test_create_polymorphic_has_one_with_scope
163
+ old_count = Tagging.count
164
+ tagging = posts(:welcome).tagging.create(:tag => tags(:misc))
165
+ assert_equal "Post", tagging.taggable_type
166
+ assert_equal old_count+1, Tagging.count
167
+ end
168
+
169
+ def test_delete_polymorphic_has_many_with_delete_all
170
+ assert_equal 1, posts(:welcome).taggings.count
171
+ posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDeleteAll'
172
+ post = find_post_with_dependency(1, :has_many, :taggings, :delete_all)
173
+
174
+ old_count = Tagging.count
175
+ post.destroy
176
+ assert_equal old_count-1, Tagging.count
177
+ assert_equal 0, posts(:welcome).taggings.count
178
+ end
179
+
180
+ def test_delete_polymorphic_has_many_with_destroy
181
+ assert_equal 1, posts(:welcome).taggings.count
182
+ posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDestroy'
183
+ post = find_post_with_dependency(1, :has_many, :taggings, :destroy)
184
+
185
+ old_count = Tagging.count
186
+ post.destroy
187
+ assert_equal old_count-1, Tagging.count
188
+ assert_equal 0, posts(:welcome).taggings.count
189
+ end
190
+
191
+ def test_delete_polymorphic_has_many_with_nullify
192
+ assert_equal 1, posts(:welcome).taggings.count
193
+ posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyNullify'
194
+ post = find_post_with_dependency(1, :has_many, :taggings, :nullify)
195
+
196
+ old_count = Tagging.count
197
+ post.destroy
198
+ assert_equal old_count, Tagging.count
199
+ assert_equal 0, posts(:welcome).taggings.count
200
+ end
201
+
202
+ def test_delete_polymorphic_has_one_with_destroy
203
+ assert posts(:welcome).tagging
204
+ posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneDestroy'
205
+ post = find_post_with_dependency(1, :has_one, :tagging, :destroy)
206
+
207
+ old_count = Tagging.count
208
+ post.destroy
209
+ assert_equal old_count-1, Tagging.count
210
+ assert_nil posts(:welcome).tagging(true)
211
+ end
212
+
213
+ def test_delete_polymorphic_has_one_with_nullify
214
+ assert posts(:welcome).tagging
215
+ posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneNullify'
216
+ post = find_post_with_dependency(1, :has_one, :tagging, :nullify)
217
+
218
+ old_count = Tagging.count
219
+ post.destroy
220
+ assert_equal old_count, Tagging.count
221
+ assert_nil posts(:welcome).tagging(true)
222
+ end
223
+
224
+ def test_has_many_with_piggyback
225
+ assert_equal "2", categories(:sti_test).authors.first.post_id.to_s
226
+ end
227
+
228
+ def test_include_has_many_through
229
+ posts = Post.find(:all, :order => 'posts.id')
230
+ posts_with_authors = Post.find(:all, :include => :authors, :order => 'posts.id')
231
+ assert_equal posts.length, posts_with_authors.length
232
+ posts.length.times do |i|
233
+ assert_equal posts[i].authors.length, assert_no_queries { posts_with_authors[i].authors.length }
234
+ end
235
+ end
236
+
237
+ def test_include_polymorphic_has_one
238
+ post = Post.find_by_id(posts(:welcome).id, :include => :tagging)
239
+ tagging = taggings(:welcome_general)
240
+ assert_no_queries do
241
+ assert_equal tagging, post.tagging
242
+ end
243
+ end
244
+
245
+ def test_include_polymorphic_has_one_defined_in_abstract_parent
246
+ item = Item.find_by_id(items(:dvd).id, :include => :tagging)
247
+ tagging = taggings(:godfather)
248
+ assert_no_queries do
249
+ assert_equal tagging, item.tagging
250
+ end
251
+ end
252
+
253
+ def test_include_polymorphic_has_many_through
254
+ posts = Post.find(:all, :order => 'posts.id')
255
+ posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
256
+ assert_equal posts.length, posts_with_tags.length
257
+ posts.length.times do |i|
258
+ assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
259
+ end
260
+ end
261
+
262
+ def test_include_polymorphic_has_many
263
+ posts = Post.find(:all, :order => 'posts.id')
264
+ posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
265
+ assert_equal posts.length, posts_with_taggings.length
266
+ posts.length.times do |i|
267
+ assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
268
+ end
269
+ end
270
+
271
+ def test_has_many_find_all
272
+ assert_equal [categories(:general)], authors(:david).categories.find(:all)
273
+ end
274
+
275
+ def test_has_many_find_first
276
+ assert_equal categories(:general), authors(:david).categories.find(:first)
277
+ end
278
+
279
+ def test_has_many_with_hash_conditions
280
+ assert_equal categories(:general), authors(:david).categories_like_general.find(:first)
281
+ end
282
+
283
+ def test_has_many_find_conditions
284
+ assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
285
+ assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
286
+ end
287
+
288
+ def test_has_many_class_methods_called_by_method_missing
289
+ assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
290
+ assert_equal nil, authors(:david).categories.find_by_name('Technology')
291
+ end
292
+
293
+ def test_has_many_going_through_join_model_with_custom_foreign_key
294
+ assert_equal [], posts(:thinking).authors
295
+ assert_equal [authors(:mary)], posts(:authorless).authors
296
+ end
297
+
298
+ def test_belongs_to_polymorphic_with_counter_cache
299
+ assert_equal 0, posts(:welcome)[:taggings_count]
300
+ tagging = posts(:welcome).taggings.create(:tag => tags(:general))
301
+ assert_equal 1, posts(:welcome, :reload)[:taggings_count]
302
+ tagging.destroy
303
+ assert posts(:welcome, :reload)[:taggings_count].zero?
304
+ end
305
+
306
+ def test_unavailable_through_reflection
307
+ assert_raises (ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
308
+ end
309
+
310
+ def test_has_many_through_join_model_with_conditions
311
+ assert_equal [], posts(:welcome).invalid_taggings
312
+ assert_equal [], posts(:welcome).invalid_tags
313
+ end
314
+
315
+ def test_has_many_polymorphic
316
+ assert_raises ActiveRecord::HasManyThroughAssociationPolymorphicError do
317
+ assert_equal posts(:welcome, :thinking), tags(:general).taggables
318
+ end
319
+ assert_raises ActiveRecord::EagerLoadPolymorphicError do
320
+ assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable)
321
+ end
322
+ end
323
+
324
+ def test_has_many_polymorphic_with_source_type
325
+ assert_equal posts(:welcome, :thinking), tags(:general).tagged_posts
326
+ end
327
+
328
+ def test_eager_has_many_polymorphic_with_source_type
329
+ tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
330
+ desired = posts(:welcome, :thinking)
331
+ assert_no_queries do
332
+ assert_equal desired, tag_with_include.tagged_posts
333
+ end
334
+ end
335
+
336
+ def test_has_many_through_has_many_find_all
337
+ assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
338
+ end
339
+
340
+ def test_has_many_through_has_many_find_all_with_custom_class
341
+ assert_equal comments(:greetings), authors(:david).funky_comments.find(:all, :order => 'comments.id').first
342
+ end
343
+
344
+ def test_has_many_through_has_many_find_first
345
+ assert_equal comments(:greetings), authors(:david).comments.find(:first, :order => 'comments.id')
346
+ end
347
+
348
+ def test_has_many_through_has_many_find_conditions
349
+ options = { :conditions => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
350
+ assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, options)
351
+ end
352
+
353
+ def test_has_many_through_has_many_find_by_id
354
+ assert_equal comments(:more_greetings), authors(:david).comments.find(2)
355
+ end
356
+
357
+ def test_has_many_through_polymorphic_has_one
358
+ assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tagging }
359
+ end
360
+
361
+ def test_has_many_through_polymorphic_has_many
362
+ assert_equal taggings(:welcome_general, :thinking_general), authors(:david).taggings.uniq.sort_by { |t| t.id }
363
+ end
364
+
365
+ def test_include_has_many_through_polymorphic_has_many
366
+ author = Author.find_by_id(authors(:david).id, :include => :taggings)
367
+ expected_taggings = taggings(:welcome_general, :thinking_general)
368
+ assert_no_queries do
369
+ assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
370
+ end
371
+ end
372
+
373
+ def test_has_many_through_has_many_through
374
+ assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tags }
375
+ end
376
+
377
+ def test_has_many_through_habtm
378
+ assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).post_categories }
379
+ end
380
+
381
+ def test_eager_load_has_many_through_has_many
382
+ author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id'
383
+ SpecialComment.new; VerySpecialComment.new
384
+ assert_no_queries do
385
+ assert_equal [1,2,3,5,6,7,8,9,10], author.comments.collect(&:id)
386
+ end
387
+ end
388
+
389
+ def test_eager_load_has_many_through_has_many_with_conditions
390
+ post = Post.find(:first, :include => :invalid_tags)
391
+ assert_no_queries do
392
+ post.invalid_tags
393
+ end
394
+ end
395
+
396
+ def test_eager_belongs_to_and_has_one_not_singularized
397
+ assert_nothing_raised do
398
+ Author.find(:first, :include => :author_address)
399
+ AuthorAddress.find(:first, :include => :author)
400
+ end
401
+ end
402
+
403
+ def test_self_referential_has_many_through
404
+ assert_equal [authors(:mary)], authors(:david).favorite_authors
405
+ assert_equal [], authors(:mary).favorite_authors
406
+ end
407
+
408
+ def test_add_to_self_referential_has_many_through
409
+ new_author = Author.create(:name => "Bob")
410
+ authors(:david).author_favorites.create :favorite_author => new_author
411
+ assert_equal new_author, authors(:david).reload.favorite_authors.first
412
+ end
413
+
414
+ def test_has_many_through_uses_conditions_specified_on_the_has_many_association
415
+ author = Author.find(:first)
416
+ assert !author.comments.blank?
417
+ assert author.nonexistant_comments.blank?
418
+ end
419
+
420
+ def test_has_many_through_uses_correct_attributes
421
+ assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
422
+ end
423
+
424
+ def test_raise_error_when_adding_new_record_to_has_many_through
425
+ assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).tags << tags(:general).clone }
426
+ assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).clone.tags << tags(:general) }
427
+ assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).tags.build }
428
+ assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).tags.new }
429
+ end
430
+
431
+ def test_create_associate_when_adding_to_has_many_through
432
+ count = posts(:thinking).tags.count
433
+ push = Tag.create!(:name => 'pushme')
434
+ post_thinking = posts(:thinking)
435
+ assert_nothing_raised { post_thinking.tags << push }
436
+ assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
437
+ message = "Expected a Tag in tags collection, got #{wrong.class}.")
438
+ assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
439
+ message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
440
+ assert_equal(count + 1, post_thinking.tags.size)
441
+ assert_equal(count + 1, post_thinking.tags(true).size)
442
+
443
+ assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo')
444
+ assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
445
+ message = "Expected a Tag in tags collection, got #{wrong.class}.")
446
+ assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
447
+ message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
448
+ assert_equal(count + 2, post_thinking.tags.size)
449
+ assert_equal(count + 2, post_thinking.tags(true).size)
450
+
451
+ assert_nothing_raised { post_thinking.tags.concat(Tag.create!(:name => 'abc'), Tag.create!(:name => 'def')) }
452
+ assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
453
+ message = "Expected a Tag in tags collection, got #{wrong.class}.")
454
+ assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
455
+ message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
456
+ assert_equal(count + 4, post_thinking.tags.size)
457
+ assert_equal(count + 4, post_thinking.tags(true).size)
458
+
459
+ # Raises if the wrong reflection name is used to set the Edge belongs_to
460
+ assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
461
+ end
462
+
463
+ def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
464
+ author = authors(:david)
465
+ assert_equal 9, author.comments.size
466
+ assert !author.comments.loaded?
467
+ end
468
+
469
+ uses_mocha('has_many_through_collection_size_uses_counter_cache_if_it_exists') do
470
+ def test_has_many_through_collection_size_uses_counter_cache_if_it_exists
471
+ author = authors(:david)
472
+ author.stubs(:read_attribute).with('comments_count').returns(100)
473
+ assert_equal 100, author.comments.size
474
+ assert !author.comments.loaded?
475
+ end
476
+ end
477
+
478
+ def test_adding_junk_to_has_many_through_should_raise_type_mismatch
479
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags << "Uhh what now?" }
480
+ end
481
+
482
+ def test_adding_to_has_many_through_should_return_self
483
+ tags = posts(:thinking).tags
484
+ assert_equal tags, posts(:thinking).tags.push(tags(:general))
485
+ end
486
+
487
+ def test_delete_associate_when_deleting_from_has_many_through_with_nonstandard_id
488
+ count = books(:awdr).references.count
489
+ references_before = books(:awdr).references
490
+ book = Book.create!(:name => 'Getting Real')
491
+ book_awdr = books(:awdr)
492
+ book_awdr.references << book
493
+ assert_equal(count + 1, book_awdr.references(true).size)
494
+
495
+ assert_nothing_raised { book_awdr.references.delete(book) }
496
+ assert_equal(count, book_awdr.references.size)
497
+ assert_equal(count, book_awdr.references(true).size)
498
+ assert_equal(references_before.sort, book_awdr.references.sort)
499
+ end
500
+
501
+ def test_delete_associate_when_deleting_from_has_many_through
502
+ count = posts(:thinking).tags.count
503
+ tags_before = posts(:thinking).tags
504
+ tag = Tag.create!(:name => 'doomed')
505
+ post_thinking = posts(:thinking)
506
+ post_thinking.tags << tag
507
+ assert_equal(count + 1, post_thinking.tags(true).size)
508
+
509
+ assert_nothing_raised { post_thinking.tags.delete(tag) }
510
+ assert_equal(count, post_thinking.tags.size)
511
+ assert_equal(count, post_thinking.tags(true).size)
512
+ assert_equal(tags_before.sort, post_thinking.tags.sort)
513
+ end
514
+
515
+ def test_delete_associate_when_deleting_from_has_many_through_with_multiple_tags
516
+ count = posts(:thinking).tags.count
517
+ tags_before = posts(:thinking).tags
518
+ doomed = Tag.create!(:name => 'doomed')
519
+ doomed2 = Tag.create!(:name => 'doomed2')
520
+ quaked = Tag.create!(:name => 'quaked')
521
+ post_thinking = posts(:thinking)
522
+ post_thinking.tags << doomed << doomed2
523
+ assert_equal(count + 2, post_thinking.tags(true).size)
524
+
525
+ assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
526
+ assert_equal(count, post_thinking.tags.size)
527
+ assert_equal(count, post_thinking.tags(true).size)
528
+ assert_equal(tags_before.sort, post_thinking.tags.sort)
529
+ end
530
+
531
+ def test_deleting_junk_from_has_many_through_should_raise_type_mismatch
532
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags.delete("Uhh what now?") }
533
+ end
534
+
535
+ def test_has_many_through_sum_uses_calculations
536
+ assert_nothing_raised { authors(:david).comments.sum(:post_id) }
537
+ end
538
+
539
+ def test_has_many_through_has_many_with_sti
540
+ assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
541
+ end
542
+
543
+ private
544
+ # create dynamic Post models to allow different dependency options
545
+ def find_post_with_dependency(post_id, association, association_name, dependency)
546
+ class_name = "PostWith#{association.to_s.classify}#{dependency.to_s.classify}"
547
+ Post.find(post_id).update_attribute :type, class_name
548
+ klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
549
+ klass.set_table_name 'posts'
550
+ klass.send(association, association_name, :as => :taggable, :dependent => dependency)
551
+ klass.find(post_id)
552
+ end
553
+ end