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