Merged updates from trunk into stable branch
[feedcatcher.git] / vendor / rails / activerecord / test / cases / associations / has_many_associations_test.rb
1 require "cases/helper"
2 require 'models/developer'
3 require 'models/project'
4 require 'models/company'
5 require 'models/topic'
6 require 'models/reply'
7 require 'models/category'
8 require 'models/post'
9 require 'models/author'
10 require 'models/comment'
11 require 'models/person'
12 require 'models/reader'
13
14 class HasManyAssociationsTest < ActiveRecord::TestCase
15 fixtures :accounts, :categories, :companies, :developers, :projects,
16 :developers_projects, :topics, :authors, :comments, :author_addresses,
17 :people, :posts, :readers
18
19 def setup
20 Client.destroyed_client_ids.clear
21 end
22
23 def force_signal37_to_load_all_clients_of_firm
24 companies(:first_firm).clients_of_firm.each {|f| }
25 end
26
27 def test_counting_with_counter_sql
28 assert_equal 2, Firm.find(:first).clients.count
29 end
30
31 def test_counting
32 assert_equal 2, Firm.find(:first).plain_clients.count
33 end
34
35 def test_counting_with_empty_hash_conditions
36 assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => {})
37 end
38
39 def test_counting_with_single_conditions
40 assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => ['name=?', "Microsoft"])
41 end
42
43 def test_counting_with_single_hash
44 assert_equal 1, Firm.find(:first).plain_clients.count(:conditions => {:name => "Microsoft"})
45 end
46
47 def test_counting_with_column_name_and_hash
48 assert_equal 2, Firm.find(:first).plain_clients.count(:name)
49 end
50
51 def test_counting_with_association_limit
52 firm = companies(:first_firm)
53 assert_equal firm.limited_clients.length, firm.limited_clients.size
54 assert_equal firm.limited_clients.length, firm.limited_clients.count
55 end
56
57 def test_finding
58 assert_equal 2, Firm.find(:first).clients.length
59 end
60
61 def test_find_with_blank_conditions
62 [[], {}, nil, ""].each do |blank|
63 assert_equal 2, Firm.find(:first).clients.find(:all, :conditions => blank).size
64 end
65 end
66
67 def test_find_many_with_merged_options
68 assert_equal 1, companies(:first_firm).limited_clients.size
69 assert_equal 1, companies(:first_firm).limited_clients.find(:all).size
70 assert_equal 2, companies(:first_firm).limited_clients.find(:all, :limit => nil).size
71 end
72
73 def test_dynamic_find_last_without_specified_order
74 assert_equal companies(:second_client), companies(:first_firm).unsorted_clients.find_last_by_type('Client')
75 end
76
77 def test_dynamic_find_should_respect_association_order
78 assert_equal companies(:second_client), companies(:first_firm).clients_sorted_desc.find(:first, :conditions => "type = 'Client'")
79 assert_equal companies(:second_client), companies(:first_firm).clients_sorted_desc.find_by_type('Client')
80 end
81
82 def test_dynamic_find_order_should_override_association_order
83 assert_equal companies(:first_client), companies(:first_firm).clients_sorted_desc.find(:first, :conditions => "type = 'Client'", :order => 'id')
84 assert_equal companies(:first_client), companies(:first_firm).clients_sorted_desc.find_by_type('Client', :order => 'id')
85 end
86
87 def test_dynamic_find_all_should_respect_association_order
88 assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.find(:all, :conditions => "type = 'Client'")
89 assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.find_all_by_type('Client')
90 end
91
92 def test_dynamic_find_all_order_should_override_association_order
93 assert_equal [companies(:first_client), companies(:second_client)], companies(:first_firm).clients_sorted_desc.find(:all, :conditions => "type = 'Client'", :order => 'id')
94 assert_equal [companies(:first_client), companies(:second_client)], companies(:first_firm).clients_sorted_desc.find_all_by_type('Client', :order => 'id')
95 end
96
97 def test_dynamic_find_all_should_respect_association_limit
98 assert_equal 1, companies(:first_firm).limited_clients.find(:all, :conditions => "type = 'Client'").length
99 assert_equal 1, companies(:first_firm).limited_clients.find_all_by_type('Client').length
100 end
101
102 def test_dynamic_find_all_limit_should_override_association_limit
103 assert_equal 2, companies(:first_firm).limited_clients.find(:all, :conditions => "type = 'Client'", :limit => 9_000).length
104 assert_equal 2, companies(:first_firm).limited_clients.find_all_by_type('Client', :limit => 9_000).length
105 end
106
107 def test_dynamic_find_all_should_respect_readonly_access
108 companies(:first_firm).readonly_clients.find(:all).each { |c| assert_raise(ActiveRecord::ReadOnlyRecord) { c.save! } }
109 companies(:first_firm).readonly_clients.find(:all).each { |c| assert c.readonly? }
110 end
111
112 def test_cant_save_has_many_readonly_association
113 authors(:david).readonly_comments.each { |c| assert_raise(ActiveRecord::ReadOnlyRecord) { c.save! } }
114 authors(:david).readonly_comments.each { |c| assert c.readonly? }
115 end
116
117 def test_triple_equality
118 assert !(Array === Firm.find(:first).clients)
119 assert Firm.find(:first).clients === Array
120 end
121
122 def test_finding_default_orders
123 assert_equal "Summit", Firm.find(:first).clients.first.name
124 end
125
126 def test_finding_with_different_class_name_and_order
127 assert_equal "Microsoft", Firm.find(:first).clients_sorted_desc.first.name
128 end
129
130 def test_finding_with_foreign_key
131 assert_equal "Microsoft", Firm.find(:first).clients_of_firm.first.name
132 end
133
134 def test_finding_with_condition
135 assert_equal "Microsoft", Firm.find(:first).clients_like_ms.first.name
136 end
137
138 def test_finding_with_condition_hash
139 assert_equal "Microsoft", Firm.find(:first).clients_like_ms_with_hash_conditions.first.name
140 end
141
142 def test_finding_using_primary_key
143 assert_equal "Summit", Firm.find(:first).clients_using_primary_key.first.name
144 end
145
146 def test_finding_using_sql
147 firm = Firm.find(:first)
148 first_client = firm.clients_using_sql.first
149 assert_not_nil first_client
150 assert_equal "Microsoft", first_client.name
151 assert_equal 1, firm.clients_using_sql.size
152 assert_equal 1, Firm.find(:first).clients_using_sql.size
153 end
154
155 def test_counting_using_sql
156 assert_equal 1, Firm.find(:first).clients_using_counter_sql.size
157 assert Firm.find(:first).clients_using_counter_sql.any?
158 assert_equal 0, Firm.find(:first).clients_using_zero_counter_sql.size
159 assert !Firm.find(:first).clients_using_zero_counter_sql.any?
160 end
161
162 def test_counting_non_existant_items_using_sql
163 assert_equal 0, Firm.find(:first).no_clients_using_counter_sql.size
164 end
165
166 def test_belongs_to_sanity
167 c = Client.new
168 assert_nil c.firm
169
170 if c.firm
171 assert false, "belongs_to failed if check"
172 end
173
174 unless c.firm
175 else
176 assert false, "belongs_to failed unless check"
177 end
178 end
179
180 def test_find_ids
181 firm = Firm.find(:first)
182
183 assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find }
184
185 client = firm.clients.find(2)
186 assert_kind_of Client, client
187
188 client_ary = firm.clients.find([2])
189 assert_kind_of Array, client_ary
190 assert_equal client, client_ary.first
191
192 client_ary = firm.clients.find(2, 3)
193 assert_kind_of Array, client_ary
194 assert_equal 2, client_ary.size
195 assert_equal client, client_ary.first
196
197 assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(2, 99) }
198 end
199
200 def test_find_string_ids_when_using_finder_sql
201 firm = Firm.find(:first)
202
203 client = firm.clients_using_finder_sql.find("2")
204 assert_kind_of Client, client
205
206 client_ary = firm.clients_using_finder_sql.find(["2"])
207 assert_kind_of Array, client_ary
208 assert_equal client, client_ary.first
209
210 client_ary = firm.clients_using_finder_sql.find("2", "3")
211 assert_kind_of Array, client_ary
212 assert_equal 2, client_ary.size
213 assert client_ary.include?(client)
214 end
215
216 def test_find_all
217 firm = Firm.find(:first)
218 assert_equal 2, firm.clients.find(:all, :conditions => "#{QUOTED_TYPE} = 'Client'").length
219 assert_equal 1, firm.clients.find(:all, :conditions => "name = 'Summit'").length
220 end
221
222 def test_find_each
223 firm = companies(:first_firm)
224
225 assert ! firm.clients.loaded?
226
227 assert_queries(3) do
228 firm.clients.find_each(:batch_size => 1) {|c| assert_equal firm.id, c.firm_id }
229 end
230
231 assert ! firm.clients.loaded?
232 end
233
234 def test_find_each_with_conditions
235 firm = companies(:first_firm)
236
237 assert_queries(2) do
238 firm.clients.find_each(:batch_size => 1, :conditions => {:name => "Microsoft"}) do |c|
239 assert_equal firm.id, c.firm_id
240 assert_equal "Microsoft", c.name
241 end
242 end
243
244 assert ! firm.clients.loaded?
245 end
246
247 def test_find_in_batches
248 firm = companies(:first_firm)
249
250 assert ! firm.clients.loaded?
251
252 assert_queries(2) do
253 firm.clients.find_in_batches(:batch_size => 2) do |clients|
254 clients.each {|c| assert_equal firm.id, c.firm_id }
255 end
256 end
257
258 assert ! firm.clients.loaded?
259 end
260
261 def test_find_all_sanitized
262 firm = Firm.find(:first)
263 summit = firm.clients.find(:all, :conditions => "name = 'Summit'")
264 assert_equal summit, firm.clients.find(:all, :conditions => ["name = ?", "Summit"])
265 assert_equal summit, firm.clients.find(:all, :conditions => ["name = :name", { :name => "Summit" }])
266 end
267
268 def test_find_first
269 firm = Firm.find(:first)
270 client2 = Client.find(2)
271 assert_equal firm.clients.first, firm.clients.find(:first)
272 assert_equal client2, firm.clients.find(:first, :conditions => "#{QUOTED_TYPE} = 'Client'")
273 end
274
275 def test_find_first_sanitized
276 firm = Firm.find(:first)
277 client2 = Client.find(2)
278 assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = ?", 'Client'])
279 assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }])
280 end
281
282 def test_find_in_collection
283 assert_equal Client.find(2).name, companies(:first_firm).clients.find(2).name
284 assert_raise(ActiveRecord::RecordNotFound) { companies(:first_firm).clients.find(6) }
285 end
286
287 def test_find_grouped
288 all_clients_of_firm1 = Client.find(:all, :conditions => "firm_id = 1")
289 grouped_clients_of_firm1 = Client.find(:all, :conditions => "firm_id = 1", :group => "firm_id", :select => 'firm_id, count(id) as clients_count')
290 assert_equal 2, all_clients_of_firm1.size
291 assert_equal 1, grouped_clients_of_firm1.size
292 end
293
294 def test_find_scoped_grouped
295 assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.size
296 assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.length
297 assert_equal 2, companies(:first_firm).clients_grouped_by_name.size
298 assert_equal 2, companies(:first_firm).clients_grouped_by_name.length
299 end
300
301 def test_find_scoped_grouped_having
302 assert_equal 1, authors(:david).popular_grouped_posts.length
303 assert_equal 0, authors(:mary).popular_grouped_posts.length
304 end
305
306 def test_adding
307 force_signal37_to_load_all_clients_of_firm
308 natural = Client.new("name" => "Natural Company")
309 companies(:first_firm).clients_of_firm << natural
310 assert_equal 2, companies(:first_firm).clients_of_firm.size # checking via the collection
311 assert_equal 2, companies(:first_firm).clients_of_firm(true).size # checking using the db
312 assert_equal natural, companies(:first_firm).clients_of_firm.last
313 end
314
315 def test_adding_using_create
316 first_firm = companies(:first_firm)
317 assert_equal 2, first_firm.plain_clients.size
318 natural = first_firm.plain_clients.create(:name => "Natural Company")
319 assert_equal 3, first_firm.plain_clients.length
320 assert_equal 3, first_firm.plain_clients.size
321 end
322
323 def test_create_with_bang_on_has_many_when_parent_is_new_raises
324 assert_raise(ActiveRecord::RecordNotSaved) do
325 firm = Firm.new
326 firm.plain_clients.create! :name=>"Whoever"
327 end
328 end
329
330 def test_regular_create_on_has_many_when_parent_is_new_raises
331 assert_raise(ActiveRecord::RecordNotSaved) do
332 firm = Firm.new
333 firm.plain_clients.create :name=>"Whoever"
334 end
335 end
336
337 def test_create_with_bang_on_has_many_raises_when_record_not_saved
338 assert_raise(ActiveRecord::RecordInvalid) do
339 firm = Firm.find(:first)
340 firm.plain_clients.create!
341 end
342 end
343
344 def test_create_with_bang_on_habtm_when_parent_is_new_raises
345 assert_raise(ActiveRecord::RecordNotSaved) do
346 Developer.new("name" => "Aredridel").projects.create!
347 end
348 end
349
350 def test_adding_a_mismatch_class
351 assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << nil }
352 assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << 1 }
353 assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << Topic.find(1) }
354 end
355
356 def test_adding_a_collection
357 force_signal37_to_load_all_clients_of_firm
358 companies(:first_firm).clients_of_firm.concat([Client.new("name" => "Natural Company"), Client.new("name" => "Apple")])
359 assert_equal 3, companies(:first_firm).clients_of_firm.size
360 assert_equal 3, companies(:first_firm).clients_of_firm(true).size
361 end
362
363 def test_build
364 company = companies(:first_firm)
365 new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") }
366 assert !company.clients_of_firm.loaded?
367
368 assert_equal "Another Client", new_client.name
369 assert new_client.new_record?
370 assert_equal new_client, company.clients_of_firm.last
371 end
372
373 def test_collection_size_after_building
374 company = companies(:first_firm) # company already has one client
375 company.clients_of_firm.build("name" => "Another Client")
376 company.clients_of_firm.build("name" => "Yet Another Client")
377 assert_equal 3, company.clients_of_firm.size
378 end
379
380 def test_collection_size_twice_for_regressions
381 post = posts(:thinking)
382 assert_equal 0, post.readers.size
383 # This test needs a post that has no readers, we assert it to ensure it holds,
384 # but need to reload the post because the very call to #size hides the bug.
385 post.reload
386 post.readers.build
387 size1 = post.readers.size
388 size2 = post.readers.size
389 assert_equal size1, size2
390 end
391
392 def test_build_many
393 company = companies(:first_firm)
394 new_clients = assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) }
395 assert_equal 2, new_clients.size
396 end
397
398 def test_build_followed_by_save_does_not_load_target
399 new_client = companies(:first_firm).clients_of_firm.build("name" => "Another Client")
400 assert companies(:first_firm).save
401 assert !companies(:first_firm).clients_of_firm.loaded?
402 end
403
404 def test_build_without_loading_association
405 first_topic = topics(:first)
406 Reply.column_names
407
408 assert_equal 1, first_topic.replies.length
409
410 assert_no_queries do
411 first_topic.replies.build(:title => "Not saved", :content => "Superstars")
412 assert_equal 2, first_topic.replies.size
413 end
414
415 assert_equal 2, first_topic.replies.to_ary.size
416 end
417
418 def test_build_via_block
419 company = companies(:first_firm)
420 new_client = assert_no_queries { company.clients_of_firm.build {|client| client.name = "Another Client" } }
421 assert !company.clients_of_firm.loaded?
422
423 assert_equal "Another Client", new_client.name
424 assert new_client.new_record?
425 assert_equal new_client, company.clients_of_firm.last
426 end
427
428 def test_build_many_via_block
429 company = companies(:first_firm)
430 new_clients = assert_no_queries do
431 company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client|
432 client.name = "changed"
433 end
434 end
435
436 assert_equal 2, new_clients.size
437 assert_equal "changed", new_clients.first.name
438 assert_equal "changed", new_clients.last.name
439 end
440
441 def test_create_without_loading_association
442 first_firm = companies(:first_firm)
443 Firm.column_names
444 Client.column_names
445
446 assert_equal 1, first_firm.clients_of_firm.size
447 first_firm.clients_of_firm.reset
448
449 assert_queries(1) do
450 first_firm.clients_of_firm.create(:name => "Superstars")
451 end
452
453 assert_equal 2, first_firm.clients_of_firm.size
454 end
455
456 def test_create
457 force_signal37_to_load_all_clients_of_firm
458 new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client")
459 assert !new_client.new_record?
460 assert_equal new_client, companies(:first_firm).clients_of_firm.last
461 assert_equal new_client, companies(:first_firm).clients_of_firm(true).last
462 end
463
464 def test_create_many
465 companies(:first_firm).clients_of_firm.create([{"name" => "Another Client"}, {"name" => "Another Client II"}])
466 assert_equal 3, companies(:first_firm).clients_of_firm(true).size
467 end
468
469 def test_create_followed_by_save_does_not_load_target
470 new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client")
471 assert companies(:first_firm).save
472 assert !companies(:first_firm).clients_of_firm.loaded?
473 end
474
475 def test_find_or_initialize
476 the_client = companies(:first_firm).clients.find_or_initialize_by_name("Yet another client")
477 assert_equal companies(:first_firm).id, the_client.firm_id
478 assert_equal "Yet another client", the_client.name
479 assert the_client.new_record?
480 end
481
482 def test_find_or_create
483 number_of_clients = companies(:first_firm).clients.size
484 the_client = companies(:first_firm).clients.find_or_create_by_name("Yet another client")
485 assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size
486 assert_equal the_client, companies(:first_firm).clients.find_or_create_by_name("Yet another client")
487 assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size
488 end
489
490 def test_deleting
491 force_signal37_to_load_all_clients_of_firm
492 companies(:first_firm).clients_of_firm.delete(companies(:first_firm).clients_of_firm.first)
493 assert_equal 0, companies(:first_firm).clients_of_firm.size
494 assert_equal 0, companies(:first_firm).clients_of_firm(true).size
495 end
496
497 def test_deleting_before_save
498 new_firm = Firm.new("name" => "A New Firm, Inc.")
499 new_client = new_firm.clients_of_firm.build("name" => "Another Client")
500 assert_equal 1, new_firm.clients_of_firm.size
501 new_firm.clients_of_firm.delete(new_client)
502 assert_equal 0, new_firm.clients_of_firm.size
503 end
504
505 def test_deleting_a_collection
506 force_signal37_to_load_all_clients_of_firm
507 companies(:first_firm).clients_of_firm.create("name" => "Another Client")
508 assert_equal 2, companies(:first_firm).clients_of_firm.size
509 companies(:first_firm).clients_of_firm.delete([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1]])
510 assert_equal 0, companies(:first_firm).clients_of_firm.size
511 assert_equal 0, companies(:first_firm).clients_of_firm(true).size
512 end
513
514 def test_delete_all
515 force_signal37_to_load_all_clients_of_firm
516 companies(:first_firm).clients_of_firm.create("name" => "Another Client")
517 assert_equal 2, companies(:first_firm).clients_of_firm.size
518 companies(:first_firm).clients_of_firm.delete_all
519 assert_equal 0, companies(:first_firm).clients_of_firm.size
520 assert_equal 0, companies(:first_firm).clients_of_firm(true).size
521 end
522
523 def test_delete_all_with_not_yet_loaded_association_collection
524 force_signal37_to_load_all_clients_of_firm
525 companies(:first_firm).clients_of_firm.create("name" => "Another Client")
526 assert_equal 2, companies(:first_firm).clients_of_firm.size
527 companies(:first_firm).clients_of_firm.reset
528 companies(:first_firm).clients_of_firm.delete_all
529 assert_equal 0, companies(:first_firm).clients_of_firm.size
530 assert_equal 0, companies(:first_firm).clients_of_firm(true).size
531 end
532
533 def test_clearing_an_association_collection
534 firm = companies(:first_firm)
535 client_id = firm.clients_of_firm.first.id
536 assert_equal 1, firm.clients_of_firm.size
537
538 firm.clients_of_firm.clear
539
540 assert_equal 0, firm.clients_of_firm.size
541 assert_equal 0, firm.clients_of_firm(true).size
542 assert_equal [], Client.destroyed_client_ids[firm.id]
543
544 # Should not be destroyed since the association is not dependent.
545 assert_nothing_raised do
546 assert Client.find(client_id).firm.nil?
547 end
548 end
549
550 def test_clearing_a_dependent_association_collection
551 firm = companies(:first_firm)
552 client_id = firm.dependent_clients_of_firm.first.id
553 assert_equal 1, firm.dependent_clients_of_firm.size
554
555 # :dependent means destroy is called on each client
556 firm.dependent_clients_of_firm.clear
557
558 assert_equal 0, firm.dependent_clients_of_firm.size
559 assert_equal 0, firm.dependent_clients_of_firm(true).size
560 assert_equal [client_id], Client.destroyed_client_ids[firm.id]
561
562 # Should be destroyed since the association is dependent.
563 assert Client.find_by_id(client_id).nil?
564 end
565
566 def test_clearing_an_exclusively_dependent_association_collection
567 firm = companies(:first_firm)
568 client_id = firm.exclusively_dependent_clients_of_firm.first.id
569 assert_equal 1, firm.exclusively_dependent_clients_of_firm.size
570
571 assert_equal [], Client.destroyed_client_ids[firm.id]
572
573 # :exclusively_dependent means each client is deleted directly from
574 # the database without looping through them calling destroy.
575 firm.exclusively_dependent_clients_of_firm.clear
576
577 assert_equal 0, firm.exclusively_dependent_clients_of_firm.size
578 assert_equal 0, firm.exclusively_dependent_clients_of_firm(true).size
579 # no destroy-filters should have been called
580 assert_equal [], Client.destroyed_client_ids[firm.id]
581
582 # Should be destroyed since the association is exclusively dependent.
583 assert Client.find_by_id(client_id).nil?
584 end
585
586 def test_dependent_association_respects_optional_conditions_on_delete
587 firm = companies(:odegy)
588 Client.create(:client_of => firm.id, :name => "BigShot Inc.")
589 Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
590 # only one of two clients is included in the association due to the :conditions key
591 assert_equal 2, Client.find_all_by_client_of(firm.id).size
592 assert_equal 1, firm.dependent_conditional_clients_of_firm.size
593 firm.destroy
594 # only the correctly associated client should have been deleted
595 assert_equal 1, Client.find_all_by_client_of(firm.id).size
596 end
597
598 def test_dependent_association_respects_optional_sanitized_conditions_on_delete
599 firm = companies(:odegy)
600 Client.create(:client_of => firm.id, :name => "BigShot Inc.")
601 Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
602 # only one of two clients is included in the association due to the :conditions key
603 assert_equal 2, Client.find_all_by_client_of(firm.id).size
604 assert_equal 1, firm.dependent_sanitized_conditional_clients_of_firm.size
605 firm.destroy
606 # only the correctly associated client should have been deleted
607 assert_equal 1, Client.find_all_by_client_of(firm.id).size
608 end
609
610 def test_dependent_association_respects_optional_hash_conditions_on_delete
611 firm = companies(:odegy)
612 Client.create(:client_of => firm.id, :name => "BigShot Inc.")
613 Client.create(:client_of => firm.id, :name => "SmallTime Inc.")
614 # only one of two clients is included in the association due to the :conditions key
615 assert_equal 2, Client.find_all_by_client_of(firm.id).size
616 assert_equal 1, firm.dependent_sanitized_conditional_clients_of_firm.size
617 firm.destroy
618 # only the correctly associated client should have been deleted
619 assert_equal 1, Client.find_all_by_client_of(firm.id).size
620 end
621
622
623 def test_creation_respects_hash_condition
624 ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.build
625
626 assert ms_client.save
627 assert_equal 'Microsoft', ms_client.name
628
629 another_ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.create
630
631 assert !another_ms_client.new_record?
632 assert_equal 'Microsoft', another_ms_client.name
633 end
634
635 def test_dependent_delete_and_destroy_with_belongs_to
636 author_address = author_addresses(:david_address)
637 assert_equal [], AuthorAddress.destroyed_author_address_ids[authors(:david).id]
638
639 assert_difference "AuthorAddress.count", -2 do
640 authors(:david).destroy
641 end
642
643 assert_equal nil, AuthorAddress.find_by_id(authors(:david).author_address_id)
644 assert_equal nil, AuthorAddress.find_by_id(authors(:david).author_address_extra_id)
645 end
646
647 def test_invalid_belongs_to_dependent_option_raises_exception
648 assert_raise ArgumentError do
649 Author.belongs_to :special_author_address, :dependent => :nullify
650 end
651 end
652
653 def test_clearing_without_initial_access
654 firm = companies(:first_firm)
655
656 firm.clients_of_firm.clear
657
658 assert_equal 0, firm.clients_of_firm.size
659 assert_equal 0, firm.clients_of_firm(true).size
660 end
661
662 def test_deleting_a_item_which_is_not_in_the_collection
663 force_signal37_to_load_all_clients_of_firm
664 summit = Client.find_by_name('Summit')
665 companies(:first_firm).clients_of_firm.delete(summit)
666 assert_equal 1, companies(:first_firm).clients_of_firm.size
667 assert_equal 1, companies(:first_firm).clients_of_firm(true).size
668 assert_equal 2, summit.client_of
669 end
670
671 def test_deleting_type_mismatch
672 david = Developer.find(1)
673 david.projects.reload
674 assert_raise(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(1) }
675 end
676
677 def test_deleting_self_type_mismatch
678 david = Developer.find(1)
679 david.projects.reload
680 assert_raise(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(Project.find(1).developers) }
681 end
682
683 def test_destroying
684 force_signal37_to_load_all_clients_of_firm
685
686 assert_difference "Client.count", -1 do
687 companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first)
688 end
689
690 assert_equal 0, companies(:first_firm).reload.clients_of_firm.size
691 assert_equal 0, companies(:first_firm).clients_of_firm(true).size
692 end
693
694 def test_destroying_a_collection
695 force_signal37_to_load_all_clients_of_firm
696 companies(:first_firm).clients_of_firm.create("name" => "Another Client")
697 assert_equal 2, companies(:first_firm).clients_of_firm.size
698
699 assert_difference "Client.count", -2 do
700 companies(:first_firm).clients_of_firm.destroy([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1]])
701 end
702
703 assert_equal 0, companies(:first_firm).reload.clients_of_firm.size
704 assert_equal 0, companies(:first_firm).clients_of_firm(true).size
705 end
706
707 def test_destroy_all
708 force_signal37_to_load_all_clients_of_firm
709 assert !companies(:first_firm).clients_of_firm.empty?, "37signals has clients after load"
710 companies(:first_firm).clients_of_firm.destroy_all
711 assert companies(:first_firm).clients_of_firm.empty?, "37signals has no clients after destroy all"
712 assert companies(:first_firm).clients_of_firm(true).empty?, "37signals has no clients after destroy all and refresh"
713 end
714
715 def test_dependence
716 firm = companies(:first_firm)
717 assert_equal 2, firm.clients.size
718 firm.destroy
719 assert Client.find(:all, :conditions => "firm_id=#{firm.id}").empty?
720 end
721
722 def test_destroy_dependent_when_deleted_from_association
723 firm = Firm.find(:first)
724 assert_equal 2, firm.clients.size
725
726 client = firm.clients.first
727 firm.clients.delete(client)
728
729 assert_raise(ActiveRecord::RecordNotFound) { Client.find(client.id) }
730 assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(client.id) }
731 assert_equal 1, firm.clients.size
732 end
733
734 def test_three_levels_of_dependence
735 topic = Topic.create "title" => "neat and simple"
736 reply = topic.replies.create "title" => "neat and simple", "content" => "still digging it"
737 silly_reply = reply.replies.create "title" => "neat and simple", "content" => "ain't complaining"
738
739 assert_nothing_raised { topic.destroy }
740 end
741
742 uses_transaction :test_dependence_with_transaction_support_on_failure
743 def test_dependence_with_transaction_support_on_failure
744 firm = companies(:first_firm)
745 clients = firm.clients
746 assert_equal 2, clients.length
747 clients.last.instance_eval { def before_destroy() raise "Trigger rollback" end }
748
749 firm.destroy rescue "do nothing"
750
751 assert_equal 2, Client.find(:all, :conditions => "firm_id=#{firm.id}").size
752 end
753
754 def test_dependence_on_account
755 num_accounts = Account.count
756 companies(:first_firm).destroy
757 assert_equal num_accounts - 1, Account.count
758 end
759
760 def test_depends_and_nullify
761 num_accounts = Account.count
762 num_companies = Company.count
763
764 core = companies(:rails_core)
765 assert_equal accounts(:rails_core_account), core.account
766 assert_equal companies(:leetsoft, :jadedpixel), core.companies
767 core.destroy
768 assert_nil accounts(:rails_core_account).reload.firm_id
769 assert_nil companies(:leetsoft).reload.client_of
770 assert_nil companies(:jadedpixel).reload.client_of
771
772
773 assert_equal num_accounts, Account.count
774 end
775
776 def test_included_in_collection
777 assert companies(:first_firm).clients.include?(Client.find(2))
778 end
779
780 def test_adding_array_and_collection
781 assert_nothing_raised { Firm.find(:first).clients + Firm.find(:all).last.clients }
782 end
783
784 def test_find_all_without_conditions
785 firm = companies(:first_firm)
786 assert_equal 2, firm.clients.find(:all).length
787 end
788
789 def test_replace_with_less
790 firm = Firm.find(:first)
791 firm.clients = [companies(:first_client)]
792 assert firm.save, "Could not save firm"
793 firm.reload
794 assert_equal 1, firm.clients.length
795 end
796
797 def test_replace_with_less_and_dependent_nullify
798 num_companies = Company.count
799 companies(:rails_core).companies = []
800 assert_equal num_companies, Company.count
801 end
802
803 def test_replace_with_new
804 firm = Firm.find(:first)
805 firm.clients = [companies(:second_client), Client.new("name" => "New Client")]
806 firm.save
807 firm.reload
808 assert_equal 2, firm.clients.length
809 assert !firm.clients.include?(:first_client)
810 end
811
812 def test_get_ids
813 assert_equal [companies(:first_client).id, companies(:second_client).id], companies(:first_firm).client_ids
814 end
815
816 def test_get_ids_for_loaded_associations
817 company = companies(:first_firm)
818 company.clients(true)
819 assert_queries(0) do
820 company.client_ids
821 company.client_ids
822 end
823 end
824
825 def test_get_ids_for_unloaded_associations_does_not_load_them
826 company = companies(:first_firm)
827 assert !company.clients.loaded?
828 assert_equal [companies(:first_client).id, companies(:second_client).id], company.client_ids
829 assert !company.clients.loaded?
830 end
831
832 def test_get_ids_for_unloaded_finder_sql_associations_loads_them
833 company = companies(:first_firm)
834 assert !company.clients_using_sql.loaded?
835 assert_equal [companies(:second_client).id], company.clients_using_sql_ids
836 assert company.clients_using_sql.loaded?
837 end
838
839 def test_assign_ids_ignoring_blanks
840 firm = Firm.create!(:name => 'Apple')
841 firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, '']
842 firm.save!
843
844 assert_equal 2, firm.clients(true).size
845 assert firm.clients.include?(companies(:second_client))
846 end
847
848 def test_get_ids_for_through
849 assert_equal [comments(:eager_other_comment1).id], authors(:mary).comment_ids
850 end
851
852 def test_modifying_a_through_a_has_many_should_raise
853 [
854 lambda { authors(:mary).comment_ids = [comments(:greetings).id, comments(:more_greetings).id] },
855 lambda { authors(:mary).comments = [comments(:greetings), comments(:more_greetings)] },
856 lambda { authors(:mary).comments << Comment.create!(:body => "Yay", :post_id => 424242) },
857 lambda { authors(:mary).comments.delete(authors(:mary).comments.first) },
858 ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasManyReflection, &block) }
859 end
860
861 def test_dynamic_find_should_respect_association_order_for_through
862 assert_equal Comment.find(10), authors(:david).comments_desc.find(:first, :conditions => "comments.type = 'SpecialComment'")
863 assert_equal Comment.find(10), authors(:david).comments_desc.find_by_type('SpecialComment')
864 end
865
866 def test_dynamic_find_order_should_override_association_order_for_through
867 assert_equal Comment.find(3), authors(:david).comments_desc.find(:first, :conditions => "comments.type = 'SpecialComment'", :order => 'comments.id')
868 assert_equal Comment.find(3), authors(:david).comments_desc.find_by_type('SpecialComment', :order => 'comments.id')
869 end
870
871 def test_dynamic_find_all_should_respect_association_order_for_through
872 assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.find(:all, :conditions => "comments.type = 'SpecialComment'")
873 assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.find_all_by_type('SpecialComment')
874 end
875
876 def test_dynamic_find_all_order_should_override_association_order_for_through
877 assert_equal [Comment.find(3), Comment.find(6), Comment.find(7), Comment.find(10)], authors(:david).comments_desc.find(:all, :conditions => "comments.type = 'SpecialComment'", :order => 'comments.id')
878 assert_equal [Comment.find(3), Comment.find(6), Comment.find(7), Comment.find(10)], authors(:david).comments_desc.find_all_by_type('SpecialComment', :order => 'comments.id')
879 end
880
881 def test_dynamic_find_all_should_respect_association_limit_for_through
882 assert_equal 1, authors(:david).limited_comments.find(:all, :conditions => "comments.type = 'SpecialComment'").length
883 assert_equal 1, authors(:david).limited_comments.find_all_by_type('SpecialComment').length
884 end
885
886 def test_dynamic_find_all_order_should_override_association_limit_for_through
887 assert_equal 4, authors(:david).limited_comments.find(:all, :conditions => "comments.type = 'SpecialComment'", :limit => 9_000).length
888 assert_equal 4, authors(:david).limited_comments.find_all_by_type('SpecialComment', :limit => 9_000).length
889 end
890
891 def test_find_all_include_over_the_same_table_for_through
892 assert_equal 2, people(:michael).posts.find(:all, :include => :people).length
893 end
894
895 def test_has_many_through_respects_hash_conditions
896 assert_equal authors(:david).hello_posts, authors(:david).hello_posts_with_hash_conditions
897 assert_equal authors(:david).hello_post_comments, authors(:david).hello_post_comments_with_hash_conditions
898 end
899
900 def test_include_uses_array_include_after_loaded
901 firm = companies(:first_firm)
902 firm.clients.class # force load target
903
904 client = firm.clients.first
905
906 assert_no_queries do
907 assert firm.clients.loaded?
908 assert firm.clients.include?(client)
909 end
910 end
911
912 def test_include_checks_if_record_exists_if_target_not_loaded
913 firm = companies(:first_firm)
914 client = firm.clients.first
915
916 firm.reload
917 assert ! firm.clients.loaded?
918 assert_queries(1) do
919 assert firm.clients.include?(client)
920 end
921 assert ! firm.clients.loaded?
922 end
923
924 def test_include_loads_collection_if_target_uses_finder_sql
925 firm = companies(:first_firm)
926 client = firm.clients_using_sql.first
927
928 firm.reload
929 assert ! firm.clients_using_sql.loaded?
930 assert firm.clients_using_sql.include?(client)
931 assert firm.clients_using_sql.loaded?
932 end
933
934
935 def test_include_returns_false_for_non_matching_record_to_verify_scoping
936 firm = companies(:first_firm)
937 client = Client.create!(:name => 'Not Associated')
938
939 assert ! firm.clients.loaded?
940 assert ! firm.clients.include?(client)
941 end
942
943 def test_calling_first_or_last_on_association_should_not_load_association
944 firm = companies(:first_firm)
945 firm.clients.first
946 firm.clients.last
947 assert !firm.clients.loaded?
948 end
949
950 def test_calling_first_or_last_on_loaded_association_should_not_fetch_with_query
951 firm = companies(:first_firm)
952 firm.clients.class # force load target
953 assert firm.clients.loaded?
954
955 assert_no_queries do
956 firm.clients.first
957 assert_equal 2, firm.clients.first(2).size
958 firm.clients.last
959 assert_equal 2, firm.clients.last(2).size
960 end
961 end
962
963 def test_calling_first_or_last_on_existing_record_with_build_should_load_association
964 firm = companies(:first_firm)
965 firm.clients.build(:name => 'Foo')
966 assert !firm.clients.loaded?
967
968 assert_queries 1 do
969 firm.clients.first
970 firm.clients.last
971 end
972
973 assert firm.clients.loaded?
974 end
975
976 def test_calling_first_or_last_on_existing_record_with_create_should_not_load_association
977 firm = companies(:first_firm)
978 firm.clients.create(:name => 'Foo')
979 assert !firm.clients.loaded?
980
981 assert_queries 2 do
982 firm.clients.first
983 firm.clients.last
984 end
985
986 assert !firm.clients.loaded?
987 end
988
989 def test_calling_first_or_last_on_new_record_should_not_run_queries
990 firm = Firm.new
991
992 assert_no_queries do
993 firm.clients.first
994 firm.clients.last
995 end
996 end
997
998 def test_calling_first_or_last_with_find_options_on_loaded_association_should_fetch_with_query
999 firm = companies(:first_firm)
1000 firm.clients.class # force load target
1001
1002 assert_queries 2 do
1003 assert firm.clients.loaded?
1004 firm.clients.first(:order => 'name')
1005 firm.clients.last(:order => 'name')
1006 end
1007 end
1008
1009 def test_calling_first_or_last_with_integer_on_association_should_load_association
1010 firm = companies(:first_firm)
1011
1012 assert_queries 1 do
1013 firm.clients.first(2)
1014 firm.clients.last(2)
1015 end
1016
1017 assert firm.clients.loaded?
1018 end
1019
1020 def test_joins_with_namespaced_model_should_use_correct_type
1021 old = ActiveRecord::Base.store_full_sti_class
1022 ActiveRecord::Base.store_full_sti_class = true
1023
1024 firm = Namespaced::Firm.create({ :name => 'Some Company' })
1025 firm.clients.create({ :name => 'Some Client' })
1026
1027 stats = Namespaced::Firm.find(firm.id, {
1028 :select => "#{Namespaced::Firm.table_name}.id, COUNT(#{Namespaced::Client.table_name}.id) AS num_clients",
1029 :joins => :clients,
1030 :group => "#{Namespaced::Firm.table_name}.id"
1031 })
1032 assert_equal 1, stats.num_clients.to_i
1033
1034 ensure
1035 ActiveRecord::Base.store_full_sti_class = old
1036 end
1037
1038 def test_association_proxy_transaction_method_starts_transaction_in_association_class
1039 Comment.expects(:transaction)
1040 Post.find(:first).comments.transaction do
1041 # nothing
1042 end
1043 end
1044
1045 def test_sending_new_to_association_proxy_should_have_same_effect_as_calling_new
1046 client_association = companies(:first_firm).clients
1047 assert_equal client_association.new.attributes, client_association.send(:new).attributes
1048 end
1049
1050 def test_respond_to_private_class_methods
1051 client_association = companies(:first_firm).clients
1052 assert !client_association.respond_to?(:private_method)
1053 assert client_association.respond_to?(:private_method, true)
1054 end
1055
1056 def test_creating_using_primary_key
1057 firm = Firm.find(:first)
1058 client = firm.clients_using_primary_key.create!(:name => 'test')
1059 assert_equal firm.name, client.firm_name
1060 end
1061 end
1062