3 require 'models/person'
4 require 'models/reference'
6 require 'models/reader'
7 require 'models/comment'
9 require 'models/tagging'
10 require 'models/author'
11 require 'models/owner'
15 class HasManyThroughAssociationsTest
< ActiveRecord
::TestCase
16 fixtures
:posts, :readers, :people, :comments, :authors, :owners, :pets, :toys
18 def test_associate_existing
19 assert_queries(2) { posts(:thinking);people(:david) }
21 posts(:thinking).people
24 posts(:thinking).people
<< people(:david)
28 assert
posts(:thinking).people
.include?(people(:david))
31 assert
posts(:thinking).reload
.people(true).include?(people(:david))
34 def test_associating_new
35 assert_queries(1) { posts(:thinking) }
36 new_person
= nil # so block binding catches it
39 new_person
= Person
.new
:first_name => 'bob'
42 # Associating new records always saves them
43 # Thus, 1 query for the new person record, 1 query for the new join table record
45 posts(:thinking).people
<< new_person
49 assert
posts(:thinking).people
.include?(new_person
)
52 assert
posts(:thinking).reload
.people(true).include?(new_person
)
55 def test_associate_new_by_building
56 assert_queries(1) { posts(:thinking) }
59 posts(:thinking).people
.build(:first_name=>"Bob")
60 posts(:thinking).people
.new(:first_name=>"Ted")
63 # Should only need to load the association once
65 assert
posts(:thinking).people
.collect(&:first_name).include?("Bob")
66 assert
posts(:thinking).people
.collect(&:first_name).include?("Ted")
69 # 2 queries for each new record (1 to save the record itself, 1 for the join model)
71 # + 1 query to save the actual post = 5
73 posts(:thinking).body
+= '-changed'
77 assert
posts(:thinking).reload
.people(true).collect(&:first_name).include?("Bob")
78 assert
posts(:thinking).reload
.people(true).collect(&:first_name).include?("Ted")
81 def test_delete_association
82 assert_queries(2){posts(:welcome);people(:michael); }
85 posts(:welcome).people
.delete(people(:michael))
89 assert
posts(:welcome).people
.empty
?
92 assert
posts(:welcome).reload
.people(true).empty
?
95 def test_destroy_association
96 assert_difference
"Person.count", -1 do
97 posts(:welcome).people
.destroy(people(:michael))
100 assert
posts(:welcome).reload
.people
.empty
?
101 assert
posts(:welcome).people(true).empty
?
105 assert_difference
"Person.count", -1 do
106 posts(:welcome).people
.destroy_all
109 assert
posts(:welcome).reload
.people
.empty
?
110 assert
posts(:welcome).people(true).empty
?
113 def test_replace_association
114 assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)}
116 # 1 query to delete the existing reader (michael)
117 # 1 query to associate the new reader (david)
119 posts(:welcome).people
= [people(:david)]
123 assert
posts(:welcome).people
.include?(people(:david))
124 assert
!posts(:welcome).people
.include?(people(:michael))
127 assert
posts(:welcome).reload
.people(true).include?(people(:david))
128 assert
!posts(:welcome).reload
.people(true).include?(people(:michael))
131 def test_associate_with_create
132 assert_queries(1) { posts(:thinking) }
134 # 1 query for the new record, 1 for the join table record
135 # No need to update the actual collection yet!
137 posts(:thinking).people
.create(:first_name=>"Jeb")
140 # *Now* we actually need the collection so it's loaded
142 assert
posts(:thinking).people
.collect(&:first_name).include?("Jeb")
145 assert
posts(:thinking).reload
.people(true).collect(&:first_name).include?("Jeb")
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
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
160 def test_clear_associations
161 assert_queries(2) { posts(:welcome);posts(:welcome).people(true) }
164 posts(:welcome).people
.clear
168 assert
posts(:welcome).people
.empty
?
171 assert
posts(:welcome).reload
.people(true).empty
?
174 def test_association_callback_ordering
177 post
= posts(:thinking)
179 post
.people_with_callbacks
<< people(:michael)
181 [:added, :before, "Michael"],
182 [:added, :after, "Michael"]
185 post
.people_with_callbacks
.push(people(:david), Person
.create
!(:first_name => "Bob"), Person
.new(:first_name => "Lary"))
187 [:added, :before, "David"],
188 [:added, :after, "David"],
189 [:added, :before, "Bob"],
190 [:added, :after, "Bob"],
191 [:added, :before, "Lary"],
192 [:added, :after, "Lary"]
195 post
.people_with_callbacks
.build(:first_name => "Ted")
197 [:added, :before, "Ted"],
198 [:added, :after, "Ted"]
201 post
.people_with_callbacks
.create(:first_name => "Sam")
203 [:added, :before, "Sam"],
204 [:added, :after, "Sam"]
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
210 [:added, :before, "Julian"],
211 [:added, :after, "Julian"],
212 [:added, :before, "Roger"],
213 [:added, :after, "Roger"]
216 post
.people_with_callbacks
.clear
217 assert_equal (%w(Michael David Julian Roger
) * 2).sort
, log
.last(8).collect(&:last).sort
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')
226 def test_count_with_include_should_alias_join_table
227 assert_equal
2, people(:michael).posts
.count(:include => :readers)
230 def test_inner_join_with_quoted_table_name
231 assert_equal
2, people(:michael).jobs
.size
235 assert_equal
[posts(:welcome).id
, posts(:authorless).id
].sort
, people(:michael).post_ids
.sort
238 def test_get_ids_for_loaded_associations
239 person
= people(:michael)
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
?
254 def test_association_proxy_transaction_method_starts_transaction_in_association_class
255 Tag
.expects(:transaction)
256 Post
.find(:first).tags
.transaction
do
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
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
276 def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
277 assert_equal
1, owners(:blackbeard).toys
.count