Updated README.rdoc again
[feedcatcher.git] / vendor / rails / activerecord / test / cases / associations / has_many_through_associations_test.rb
1 require "cases/helper"
2 require 'models/post'
3 require 'models/person'
4 require 'models/reference'
5 require 'models/job'
6 require 'models/reader'
7 require 'models/comment'
8 require 'models/tag'
9 require 'models/tagging'
10 require 'models/author'
11 require 'models/owner'
12 require 'models/pet'
13 require 'models/toy'
14
15 class HasManyThroughAssociationsTest < ActiveRecord::TestCase
16 fixtures :posts, :readers, :people, :comments, :authors, :owners, :pets, :toys
17
18 def test_associate_existing
19 assert_queries(2) { posts(:thinking);people(:david) }
20
21 posts(:thinking).people
22
23 assert_queries(1) do
24 posts(:thinking).people << people(:david)
25 end
26
27 assert_queries(1) do
28 assert posts(:thinking).people.include?(people(:david))
29 end
30
31 assert posts(:thinking).reload.people(true).include?(people(:david))
32 end
33
34 def test_associating_new
35 assert_queries(1) { posts(:thinking) }
36 new_person = nil # so block binding catches it
37
38 assert_queries(0) do
39 new_person = Person.new :first_name => 'bob'
40 end
41
42 # Associating new records always saves them
43 # Thus, 1 query for the new person record, 1 query for the new join table record
44 assert_queries(2) do
45 posts(:thinking).people << new_person
46 end
47
48 assert_queries(1) do
49 assert posts(:thinking).people.include?(new_person)
50 end
51
52 assert posts(:thinking).reload.people(true).include?(new_person)
53 end
54
55 def test_associate_new_by_building
56 assert_queries(1) { posts(:thinking) }
57
58 assert_queries(0) do
59 posts(:thinking).people.build(:first_name=>"Bob")
60 posts(:thinking).people.new(:first_name=>"Ted")
61 end
62
63 # Should only need to load the association once
64 assert_queries(1) do
65 assert posts(:thinking).people.collect(&:first_name).include?("Bob")
66 assert posts(:thinking).people.collect(&:first_name).include?("Ted")
67 end
68
69 # 2 queries for each new record (1 to save the record itself, 1 for the join model)
70 # * 2 new records = 4
71 # + 1 query to save the actual post = 5
72 assert_queries(5) do
73 posts(:thinking).body += '-changed'
74 posts(:thinking).save
75 end
76
77 assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Bob")
78 assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Ted")
79 end
80
81 def test_delete_association
82 assert_queries(2){posts(:welcome);people(:michael); }
83
84 assert_queries(1) do
85 posts(:welcome).people.delete(people(:michael))
86 end
87
88 assert_queries(1) do
89 assert posts(:welcome).people.empty?
90 end
91
92 assert posts(:welcome).reload.people(true).empty?
93 end
94
95 def test_destroy_association
96 assert_difference "Person.count", -1 do
97 posts(:welcome).people.destroy(people(:michael))
98 end
99
100 assert posts(:welcome).reload.people.empty?
101 assert posts(:welcome).people(true).empty?
102 end
103
104 def test_destroy_all
105 assert_difference "Person.count", -1 do
106 posts(:welcome).people.destroy_all
107 end
108
109 assert posts(:welcome).reload.people.empty?
110 assert posts(:welcome).people(true).empty?
111 end
112
113 def test_replace_association
114 assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)}
115
116 # 1 query to delete the existing reader (michael)
117 # 1 query to associate the new reader (david)
118 assert_queries(2) do
119 posts(:welcome).people = [people(:david)]
120 end
121
122 assert_queries(0){
123 assert posts(:welcome).people.include?(people(:david))
124 assert !posts(:welcome).people.include?(people(:michael))
125 }
126
127 assert posts(:welcome).reload.people(true).include?(people(:david))
128 assert !posts(:welcome).reload.people(true).include?(people(:michael))
129 end
130
131 def test_associate_with_create
132 assert_queries(1) { posts(:thinking) }
133
134 # 1 query for the new record, 1 for the join table record
135 # No need to update the actual collection yet!
136 assert_queries(2) do
137 posts(:thinking).people.create(:first_name=>"Jeb")
138 end
139
140 # *Now* we actually need the collection so it's loaded
141 assert_queries(1) do
142 assert posts(:thinking).people.collect(&:first_name).include?("Jeb")
143 end
144
145 assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Jeb")
146 end
147
148 def test_associate_with_create_and_no_options
149 peeps = posts(:thinking).people.count
150 posts(:thinking).people.create(:first_name => 'foo')
151 assert_equal peeps + 1, posts(:thinking).people.count
152 end
153
154 def test_associate_with_create_exclamation_and_no_options
155 peeps = posts(:thinking).people.count
156 posts(:thinking).people.create!(:first_name => 'foo')
157 assert_equal peeps + 1, posts(:thinking).people.count
158 end
159
160 def test_clear_associations
161 assert_queries(2) { posts(:welcome);posts(:welcome).people(true) }
162
163 assert_queries(1) do
164 posts(:welcome).people.clear
165 end
166
167 assert_queries(0) do
168 assert posts(:welcome).people.empty?
169 end
170
171 assert posts(:welcome).reload.people(true).empty?
172 end
173
174 def test_association_callback_ordering
175 Post.reset_log
176 log = Post.log
177 post = posts(:thinking)
178
179 post.people_with_callbacks << people(:michael)
180 assert_equal [
181 [:added, :before, "Michael"],
182 [:added, :after, "Michael"]
183 ], log.last(2)
184
185 post.people_with_callbacks.push(people(:david), Person.create!(:first_name => "Bob"), Person.new(:first_name => "Lary"))
186 assert_equal [
187 [:added, :before, "David"],
188 [:added, :after, "David"],
189 [:added, :before, "Bob"],
190 [:added, :after, "Bob"],
191 [:added, :before, "Lary"],
192 [:added, :after, "Lary"]
193 ],log.last(6)
194
195 post.people_with_callbacks.build(:first_name => "Ted")
196 assert_equal [
197 [:added, :before, "Ted"],
198 [:added, :after, "Ted"]
199 ], log.last(2)
200
201 post.people_with_callbacks.create(:first_name => "Sam")
202 assert_equal [
203 [:added, :before, "Sam"],
204 [:added, :after, "Sam"]
205 ], log.last(2)
206
207 post.people_with_callbacks = [people(:michael),people(:david), Person.new(:first_name => "Julian"), Person.create!(:first_name => "Roger")]
208 assert_equal (%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort
209 assert_equal [
210 [:added, :before, "Julian"],
211 [:added, :after, "Julian"],
212 [:added, :before, "Roger"],
213 [:added, :after, "Roger"]
214 ], log.last(4)
215
216 post.people_with_callbacks.clear
217 assert_equal (%w(Michael David Julian Roger) * 2).sort, log.last(8).collect(&:last).sort
218 end
219
220 def test_dynamic_find_should_respect_association_include
221 # SQL error in sort clause if :include is not included
222 # due to Unknown column 'comments.id'
223 assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title('Welcome to the weblog')
224 end
225
226 def test_count_with_include_should_alias_join_table
227 assert_equal 2, people(:michael).posts.count(:include => :readers)
228 end
229
230 def test_inner_join_with_quoted_table_name
231 assert_equal 2, people(:michael).jobs.size
232 end
233
234 def test_get_ids
235 assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort
236 end
237
238 def test_get_ids_for_loaded_associations
239 person = people(:michael)
240 person.posts(true)
241 assert_queries(0) do
242 person.post_ids
243 person.post_ids
244 end
245 end
246
247 def test_get_ids_for_unloaded_associations_does_not_load_them
248 person = people(:michael)
249 assert !person.posts.loaded?
250 assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort
251 assert !person.posts.loaded?
252 end
253
254 def test_association_proxy_transaction_method_starts_transaction_in_association_class
255 Tag.expects(:transaction)
256 Post.find(:first).tags.transaction do
257 # nothing
258 end
259 end
260
261 def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist
262 author = authors(:mary)
263 post = Post.create!(:title => "TITLE", :body => "BODY")
264 assert_equal [], post.author_favorites
265 end
266
267 def test_has_many_association_through_a_belongs_to_association
268 author = authors(:mary)
269 post = Post.create!(:author => author, :title => "TITLE", :body => "BODY")
270 author.author_favorites.create(:favorite_author_id => 1)
271 author.author_favorites.create(:favorite_author_id => 2)
272 author.author_favorites.create(:favorite_author_id => 3)
273 assert_equal post.author.author_favorites, post.author_favorites
274 end
275
276 def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
277 assert_equal 1, owners(:blackbeard).toys.count
278 end
279 end