activerecord 1.14.4 → 1.15.0

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

Potentially problematic release.


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

Files changed (159) hide show
  1. data/CHANGELOG +400 -1
  2. data/README +2 -2
  3. data/RUNNING_UNIT_TESTS +21 -3
  4. data/Rakefile +55 -10
  5. data/lib/active_record.rb +10 -4
  6. data/lib/active_record/acts/list.rb +15 -4
  7. data/lib/active_record/acts/nested_set.rb +11 -12
  8. data/lib/active_record/acts/tree.rb +13 -14
  9. data/lib/active_record/aggregations.rb +46 -22
  10. data/lib/active_record/associations.rb +213 -162
  11. data/lib/active_record/associations/association_collection.rb +45 -15
  12. data/lib/active_record/associations/association_proxy.rb +32 -13
  13. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +18 -18
  14. data/lib/active_record/associations/has_many_association.rb +37 -17
  15. data/lib/active_record/associations/has_many_through_association.rb +120 -30
  16. data/lib/active_record/associations/has_one_association.rb +1 -1
  17. data/lib/active_record/attribute_methods.rb +75 -0
  18. data/lib/active_record/base.rb +282 -203
  19. data/lib/active_record/calculations.rb +95 -54
  20. data/lib/active_record/callbacks.rb +13 -24
  21. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +12 -1
  22. data/lib/active_record/connection_adapters/abstract/connection_specification.rb.rej +21 -0
  23. data/lib/active_record/connection_adapters/abstract/database_statements.rb +30 -4
  24. data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -9
  25. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +121 -37
  26. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +55 -23
  27. data/lib/active_record/connection_adapters/abstract_adapter.rb +8 -0
  28. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -11
  29. data/lib/active_record/connection_adapters/firebird_adapter.rb +364 -50
  30. data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
  31. data/lib/active_record/connection_adapters/mysql_adapter.rb +86 -33
  32. data/lib/active_record/connection_adapters/openbase_adapter.rb +4 -3
  33. data/lib/active_record/connection_adapters/oracle_adapter.rb +151 -127
  34. data/lib/active_record/connection_adapters/postgresql_adapter.rb +125 -48
  35. data/lib/active_record/connection_adapters/sqlite_adapter.rb +38 -10
  36. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +183 -155
  37. data/lib/active_record/connection_adapters/sybase_adapter.rb +190 -212
  38. data/lib/active_record/deprecated_associations.rb +24 -10
  39. data/lib/active_record/deprecated_finders.rb +4 -1
  40. data/lib/active_record/fixtures.rb +37 -23
  41. data/lib/active_record/locking/optimistic.rb +106 -0
  42. data/lib/active_record/locking/pessimistic.rb +77 -0
  43. data/lib/active_record/migration.rb +8 -5
  44. data/lib/active_record/observer.rb +73 -34
  45. data/lib/active_record/reflection.rb +21 -7
  46. data/lib/active_record/schema_dumper.rb +33 -5
  47. data/lib/active_record/timestamp.rb +23 -34
  48. data/lib/active_record/transactions.rb +37 -30
  49. data/lib/active_record/validations.rb +46 -30
  50. data/lib/active_record/vendor/mysql.rb +20 -5
  51. data/lib/active_record/version.rb +2 -2
  52. data/lib/active_record/wrappings.rb +1 -2
  53. data/lib/active_record/xml_serialization.rb +308 -0
  54. data/test/aaa_create_tables_test.rb +5 -1
  55. data/test/abstract_unit.rb +18 -8
  56. data/test/{active_schema_mysql.rb → active_schema_test_mysql.rb} +2 -2
  57. data/test/adapter_test.rb +9 -7
  58. data/test/adapter_test_sqlserver.rb +81 -0
  59. data/test/aggregations_test.rb +29 -0
  60. data/test/{association_callbacks_test.rb → associations/callbacks_test.rb} +10 -8
  61. data/test/{associations_cascaded_eager_loading_test.rb → associations/cascaded_eager_loading_test.rb} +35 -3
  62. data/test/{associations_go_eager_test.rb → associations/eager_test.rb} +36 -2
  63. data/test/{associations_extensions_test.rb → associations/extension_test.rb} +5 -0
  64. data/test/{associations_join_model_test.rb → associations/join_model_test.rb} +118 -8
  65. data/test/associations_test.rb +339 -45
  66. data/test/attribute_methods_test.rb +49 -0
  67. data/test/base_test.rb +321 -67
  68. data/test/calculations_test.rb +48 -10
  69. data/test/callbacks_test.rb +13 -0
  70. data/test/connection_test_firebird.rb +8 -0
  71. data/test/connections/native_db2/connection.rb +18 -17
  72. data/test/connections/native_firebird/connection.rb +19 -17
  73. data/test/connections/native_frontbase/connection.rb +27 -0
  74. data/test/connections/native_mysql/connection.rb +18 -15
  75. data/test/connections/native_openbase/connection.rb +14 -15
  76. data/test/connections/native_oracle/connection.rb +16 -12
  77. data/test/connections/native_postgresql/connection.rb +16 -17
  78. data/test/connections/native_sqlite/connection.rb +3 -6
  79. data/test/connections/native_sqlite3/connection.rb +3 -6
  80. data/test/connections/native_sqlserver/connection.rb +16 -17
  81. data/test/connections/native_sqlserver_odbc/connection.rb +18 -19
  82. data/test/connections/native_sybase/connection.rb +16 -17
  83. data/test/datatype_test_postgresql.rb +52 -0
  84. data/test/defaults_test.rb +52 -10
  85. data/test/deprecated_associations_test.rb +151 -107
  86. data/test/deprecated_finder_test.rb +83 -66
  87. data/test/empty_date_time_test.rb +25 -0
  88. data/test/finder_test.rb +118 -11
  89. data/test/fixtures/accounts.yml +6 -1
  90. data/test/fixtures/author.rb +27 -4
  91. data/test/fixtures/categorizations.yml +8 -2
  92. data/test/fixtures/category.rb +1 -2
  93. data/test/fixtures/comments.yml +0 -6
  94. data/test/fixtures/companies.yml +6 -1
  95. data/test/fixtures/company.rb +23 -1
  96. data/test/fixtures/company_in_module.rb +8 -10
  97. data/test/fixtures/customer.rb +2 -2
  98. data/test/fixtures/customers.yml +9 -0
  99. data/test/fixtures/db_definitions/db2.drop.sql +1 -0
  100. data/test/fixtures/db_definitions/db2.sql +9 -0
  101. data/test/fixtures/db_definitions/firebird.drop.sql +3 -0
  102. data/test/fixtures/db_definitions/firebird.sql +13 -1
  103. data/test/fixtures/db_definitions/frontbase.drop.sql +31 -0
  104. data/test/fixtures/db_definitions/frontbase.sql +262 -0
  105. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  106. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  107. data/test/fixtures/db_definitions/mysql.drop.sql +1 -0
  108. data/test/fixtures/db_definitions/mysql.sql +23 -14
  109. data/test/fixtures/db_definitions/openbase.sql +13 -1
  110. data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
  111. data/test/fixtures/db_definitions/oracle.sql +29 -2
  112. data/test/fixtures/db_definitions/postgresql.drop.sql +3 -1
  113. data/test/fixtures/db_definitions/postgresql.sql +13 -3
  114. data/test/fixtures/db_definitions/schema.rb +29 -1
  115. data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
  116. data/test/fixtures/db_definitions/sqlite.sql +12 -3
  117. data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
  118. data/test/fixtures/db_definitions/sqlserver.sql +35 -0
  119. data/test/fixtures/db_definitions/sybase.drop.sql +2 -0
  120. data/test/fixtures/db_definitions/sybase.sql +13 -4
  121. data/test/fixtures/developer.rb +12 -0
  122. data/test/fixtures/edge.rb +5 -0
  123. data/test/fixtures/edges.yml +6 -0
  124. data/test/fixtures/funny_jokes.yml +3 -7
  125. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  126. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  127. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  128. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  129. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  130. data/test/fixtures/mixin.rb +15 -0
  131. data/test/fixtures/mixins.yml +38 -0
  132. data/test/fixtures/post.rb +3 -2
  133. data/test/fixtures/project.rb +3 -1
  134. data/test/fixtures/topic.rb +6 -1
  135. data/test/fixtures/topics.yml +4 -4
  136. data/test/fixtures/vertex.rb +9 -0
  137. data/test/fixtures/vertices.yml +4 -0
  138. data/test/fixtures_test.rb +45 -0
  139. data/test/inheritance_test.rb +67 -6
  140. data/test/lifecycle_test.rb +40 -19
  141. data/test/locking_test.rb +170 -26
  142. data/test/method_scoping_test.rb +2 -2
  143. data/test/migration_test.rb +387 -110
  144. data/test/migration_test_firebird.rb +124 -0
  145. data/test/mixin_nested_set_test.rb +14 -2
  146. data/test/mixin_test.rb +56 -18
  147. data/test/modules_test.rb +8 -2
  148. data/test/multiple_db_test.rb +2 -2
  149. data/test/pk_test.rb +1 -0
  150. data/test/reflection_test.rb +8 -2
  151. data/test/schema_authorization_test_postgresql.rb +75 -0
  152. data/test/schema_dumper_test.rb +40 -4
  153. data/test/table_name_test_sqlserver.rb +23 -0
  154. data/test/threaded_connections_test.rb +19 -16
  155. data/test/transactions_test.rb +86 -72
  156. data/test/validations_test.rb +126 -56
  157. data/test/xml_serialization_test.rb +125 -0
  158. metadata +45 -11
  159. data/lib/active_record/locking.rb +0 -79
@@ -11,33 +11,34 @@ require 'fixtures/category'
11
11
  require 'fixtures/post'
12
12
  require 'fixtures/author'
13
13
 
14
- # Can't declare new classes in test case methods, so tests before that
15
- bad_collection_keys = false
16
- begin
17
- class Car < ActiveRecord::Base; has_many :wheels, :name => "wheels"; end
18
- rescue ArgumentError
19
- bad_collection_keys = true
20
- end
21
- raise "ActiveRecord should have barked on bad collection keys" unless bad_collection_keys
22
-
23
14
 
24
15
  class AssociationsTest < Test::Unit::TestCase
25
16
  fixtures :accounts, :companies, :developers, :projects, :developers_projects,
26
17
  :computers
27
18
 
19
+ def test_bad_collection_keys
20
+ assert_raise(ArgumentError, 'ActiveRecord should have barked on bad collection keys') do
21
+ Class.new(ActiveRecord::Base).has_many(:wheels, :name => 'wheels')
22
+ end
23
+ end
24
+
28
25
  def test_force_reload
29
26
  firm = Firm.new("name" => "A New Firm, Inc")
30
27
  firm.save
31
28
  firm.clients.each {|c|} # forcing to load all clients
32
29
  assert firm.clients.empty?, "New firm shouldn't have client objects"
33
- assert !firm.has_clients?, "New firm shouldn't have clients"
30
+ assert_deprecated do
31
+ assert !firm.has_clients?, "New firm shouldn't have clients"
32
+ end
34
33
  assert_equal 0, firm.clients.size, "New firm should have 0 clients"
35
34
 
36
35
  client = Client.new("name" => "TheClient.com", "firm_id" => firm.id)
37
36
  client.save
38
37
 
39
38
  assert firm.clients.empty?, "New firm should have cached no client objects"
40
- assert !firm.has_clients?, "New firm should have cached a no-clients response"
39
+ assert_deprecated do
40
+ assert !firm.has_clients?, "New firm should have cached a no-clients response"
41
+ end
41
42
  assert_equal 0, firm.clients.size, "New firm should have cached 0 clients count"
42
43
 
43
44
  assert !firm.clients(true).empty?, "New firm should have reloaded client objects"
@@ -65,14 +66,62 @@ class AssociationsTest < Test::Unit::TestCase
65
66
  end
66
67
  end
67
68
 
69
+ class AssociationProxyTest < Test::Unit::TestCase
70
+ fixtures :authors, :posts
71
+
72
+ def test_proxy_accessors
73
+ welcome = posts(:welcome)
74
+ assert_equal welcome, welcome.author.proxy_owner
75
+ assert_equal welcome.class.reflect_on_association(:author), welcome.author.proxy_reflection
76
+ welcome.author.class # force load target
77
+ assert_equal welcome.author, welcome.author.proxy_target
78
+
79
+ david = authors(:david)
80
+ assert_equal david, david.posts.proxy_owner
81
+ assert_equal david.class.reflect_on_association(:posts), david.posts.proxy_reflection
82
+ david.posts.first # force load target
83
+ assert_equal david.posts, david.posts.proxy_target
84
+
85
+ assert_equal david, david.posts_with_extension.testing_proxy_owner
86
+ assert_equal david.class.reflect_on_association(:posts_with_extension), david.posts_with_extension.testing_proxy_reflection
87
+ david.posts_with_extension.first # force load target
88
+ assert_equal david.posts_with_extension, david.posts_with_extension.testing_proxy_target
89
+ end
90
+ end
91
+
68
92
  class HasOneAssociationsTest < Test::Unit::TestCase
69
93
  fixtures :accounts, :companies, :developers, :projects, :developers_projects
70
94
 
95
+ def setup
96
+ Account.destroyed_account_ids.clear
97
+ end
98
+
71
99
  def test_has_one
72
100
  assert_equal companies(:first_firm).account, Account.find(1)
73
101
  assert_equal Account.find(1).credit_limit, companies(:first_firm).account.credit_limit
74
102
  end
75
103
 
104
+ def test_has_one_cache_nils
105
+ firm = companies(:another_firm)
106
+ assert_queries(1) { assert_nil firm.account }
107
+ assert_queries(0) { assert_nil firm.account }
108
+
109
+ firms = Firm.find(:all, :include => :account)
110
+ assert_queries(0) { firms.each(&:account) }
111
+ end
112
+
113
+ def test_can_marshal_has_one_association_with_nil_target
114
+ firm = Firm.new
115
+ assert_nothing_raised do
116
+ assert_equal firm.attributes, Marshal.load(Marshal.dump(firm)).attributes
117
+ end
118
+
119
+ firm.account
120
+ assert_nothing_raised do
121
+ assert_equal firm.attributes, Marshal.load(Marshal.dump(firm)).attributes
122
+ end
123
+ end
124
+
76
125
  def test_proxy_assignment
77
126
  company = companies(:first_firm)
78
127
  assert_nothing_raised { company.account = company.account }
@@ -135,10 +184,40 @@ class HasOneAssociationsTest < Test::Unit::TestCase
135
184
 
136
185
  def test_dependence
137
186
  num_accounts = Account.count
187
+
138
188
  firm = Firm.find(1)
139
189
  assert !firm.account.nil?
140
- firm.destroy
190
+ account_id = firm.account.id
191
+ assert_equal [], Account.destroyed_account_ids[firm.id]
192
+
193
+ firm.destroy
194
+ assert_equal num_accounts - 1, Account.count
195
+ assert_equal [account_id], Account.destroyed_account_ids[firm.id]
196
+ end
197
+
198
+ def test_deprecated_exclusive_dependence
199
+ assert_deprecated(/:exclusively_dependent.*:dependent => :delete_all/) do
200
+ Firm.has_many :deprecated_exclusively_dependent_clients, :class_name => 'Client', :exclusively_dependent => true
201
+ end
202
+ end
203
+
204
+ def test_exclusive_dependence
205
+ num_accounts = Account.count
206
+
207
+ firm = ExclusivelyDependentFirm.find(9)
208
+ assert !firm.account.nil?
209
+ account_id = firm.account.id
210
+ assert_equal [], Account.destroyed_account_ids[firm.id]
211
+
212
+ firm.destroy
141
213
  assert_equal num_accounts - 1, Account.count
214
+ assert_equal [], Account.destroyed_account_ids[firm.id]
215
+ end
216
+
217
+ def test_dependence_with_nil_associate
218
+ firm = DependentFirm.new(:name => 'nullify')
219
+ firm.save!
220
+ assert_nothing_raised { firm.destroy }
142
221
  end
143
222
 
144
223
  def test_succesful_build_association
@@ -247,6 +326,14 @@ class HasOneAssociationsTest < Test::Unit::TestCase
247
326
  assert_equal a, firm.account(true)
248
327
  end
249
328
 
329
+ def test_finding_with_interpolated_condition
330
+ firm = Firm.find(:first)
331
+ superior = firm.clients.create(:name => 'SuperiorCo')
332
+ superior.rating = 10
333
+ superior.save
334
+ assert_equal 10, firm.clients_with_interpolated_conditions.first.rating
335
+ end
336
+
250
337
  def test_assignment_before_child_saved
251
338
  firm = Firm.find(1)
252
339
  firm.account = a = Account.new("credit_limit" => 1000)
@@ -268,6 +355,40 @@ class HasOneAssociationsTest < Test::Unit::TestCase
268
355
  assert_equal a, firm.account
269
356
  assert_equal a, firm.account(true)
270
357
  end
358
+
359
+ def test_not_resaved_when_unchanged
360
+ firm = Firm.find(:first, :include => :account)
361
+ assert_queries(1) { firm.save! }
362
+
363
+ firm = Firm.find(:first)
364
+ firm.account = Account.find(:first)
365
+ assert_queries(1) { firm.save! }
366
+
367
+ firm = Firm.find(:first).clone
368
+ firm.account = Account.find(:first)
369
+ assert_queries(2) { firm.save! }
370
+
371
+ firm = Firm.find(:first).clone
372
+ firm.account = Account.find(:first).clone
373
+ assert_queries(2) { firm.save! }
374
+ end
375
+
376
+ def test_save_still_works_after_accessing_nil_has_one
377
+ jp = Company.new :name => 'Jaded Pixel'
378
+ jp.dummy_account.nil?
379
+
380
+ assert_nothing_raised do
381
+ jp.save!
382
+ end
383
+ end
384
+
385
+ def test_deprecated_inferred_foreign_key
386
+ assert_not_deprecated { Company.belongs_to :firm }
387
+ assert_not_deprecated { Company.belongs_to :client, :foreign_key => "firm_id" }
388
+ assert_not_deprecated { Company.belongs_to :firm, :class_name => "Firm", :foreign_key => "client_of" }
389
+ assert_deprecated("inferred foreign_key name") { Company.belongs_to :client, :class_name => "Firm" }
390
+ end
391
+
271
392
  end
272
393
 
273
394
 
@@ -283,10 +404,28 @@ class HasManyAssociationsTest < Test::Unit::TestCase
283
404
  companies(:first_firm).clients_of_firm.each {|f| }
284
405
  end
285
406
 
286
- def test_counting
407
+ def test_counting_with_counter_sql
287
408
  assert_equal 2, Firm.find(:first).clients.count
288
409
  end
289
-
410
+
411
+ def test_counting
412
+ assert_equal 2, Firm.find(:first).plain_clients.count
413
+ end
414
+
415
+ def test_counting_with_single_conditions
416
+ assert_deprecated 'count' do
417
+ assert_equal 2, Firm.find(:first).plain_clients.count('1=1')
418
+ end
419
+ end
420
+
421
+ def test_counting_with_single_hash
422
+ assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => '1=1')
423
+ end
424
+
425
+ def test_counting_with_column_name_and_hash
426
+ assert_equal 2, Firm.find(:first).plain_clients.count(:all, :conditions => '1=1')
427
+ end
428
+
290
429
  def test_finding
291
430
  assert_equal 2, Firm.find(:first).clients.length
292
431
  end
@@ -318,6 +457,10 @@ class HasManyAssociationsTest < Test::Unit::TestCase
318
457
  assert_equal "Microsoft", Firm.find(:first).clients_like_ms.first.name
319
458
  end
320
459
 
460
+ def test_finding_with_condition_hash
461
+ assert_equal "Microsoft", Firm.find(:first).clients_like_ms_with_hash_conditions.first.name
462
+ end
463
+
321
464
  def test_finding_using_sql
322
465
  firm = Firm.find(:first)
323
466
  first_client = firm.clients_using_sql.first
@@ -371,34 +514,44 @@ class HasManyAssociationsTest < Test::Unit::TestCase
371
514
  end
372
515
 
373
516
  def test_find_all
374
- firm = Firm.find_first
375
- assert_equal firm.clients, firm.clients.find_all
376
- assert_equal 2, firm.clients.find(:all, :conditions => "#{QUOTED_TYPE} = 'Client'").length
377
- assert_equal 1, firm.clients.find(:all, :conditions => "name = 'Summit'").length
517
+ assert_deprecated 'find_all' do
518
+ firm = Firm.find_first
519
+ assert_equal firm.clients, firm.clients.find_all
520
+ assert_equal 2, firm.clients.find(:all, :conditions => "#{QUOTED_TYPE} = 'Client'").length
521
+ assert_equal 1, firm.clients.find(:all, :conditions => "name = 'Summit'").length
522
+ end
378
523
  end
379
524
 
380
525
  def test_find_all_sanitized
381
- firm = Firm.find_first
382
- assert_equal firm.clients.find_all("name = 'Summit'"), firm.clients.find_all(["name = '%s'", "Summit"])
383
- summit = firm.clients.find(:all, :conditions => "name = 'Summit'")
384
- assert_equal summit, firm.clients.find(:all, :conditions => ["name = ?", "Summit"])
385
- assert_equal summit, firm.clients.find(:all, :conditions => ["name = :name", { :name => "Summit" }])
526
+ assert_deprecated 'find_all' do
527
+ firm = Firm.find_first
528
+ assert_equal firm.clients.find_all("name = 'Summit'"), firm.clients.find_all(["name = '%s'", "Summit"])
529
+ summit = firm.clients.find(:all, :conditions => "name = 'Summit'")
530
+ assert_equal summit, firm.clients.find(:all, :conditions => ["name = ?", "Summit"])
531
+ assert_equal summit, firm.clients.find(:all, :conditions => ["name = :name", { :name => "Summit" }])
532
+ end
386
533
  end
387
534
 
388
535
  def test_find_first
389
- firm = Firm.find_first
390
- client2 = Client.find(2)
391
- assert_equal firm.clients.first, firm.clients.find_first
392
- assert_equal client2, firm.clients.find_first("#{QUOTED_TYPE} = 'Client'")
393
- assert_equal client2, firm.clients.find(:first, :conditions => "#{QUOTED_TYPE} = 'Client'")
536
+ assert_deprecated 'find_first' do
537
+ firm = Firm.find_first
538
+ client2 = Client.find(2)
539
+ assert_equal firm.clients.first, firm.clients.find_first
540
+ assert_equal client2, firm.clients.find_first("#{QUOTED_TYPE} = 'Client'")
541
+ assert_equal client2, firm.clients.find(:first, :conditions => "#{QUOTED_TYPE} = 'Client'")
542
+ end
394
543
  end
395
544
 
396
545
  def test_find_first_sanitized
397
- firm = Firm.find_first
398
- client2 = Client.find(2)
399
- assert_equal client2, firm.clients.find_first(["#{QUOTED_TYPE} = ?", "Client"])
400
- assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = ?", 'Client'])
401
- assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }])
546
+ assert_deprecated 'find_first' do
547
+ firm = Firm.find_first
548
+ client2 = Client.find(2)
549
+ assert_deprecated(/find_first/) do
550
+ assert_equal client2, firm.clients.find_first(["#{QUOTED_TYPE} = ?", "Client"])
551
+ end
552
+ assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = ?", 'Client'])
553
+ assert_equal client2, firm.clients.find(:first, :conditions => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }])
554
+ end
402
555
  end
403
556
 
404
557
  def test_find_in_collection
@@ -421,6 +574,14 @@ class HasManyAssociationsTest < Test::Unit::TestCase
421
574
  assert_equal 2, companies(:first_firm).clients_of_firm(true).size # checking using the db
422
575
  assert_equal natural, companies(:first_firm).clients_of_firm.last
423
576
  end
577
+
578
+ def test_adding_using_create
579
+ first_firm = companies(:first_firm)
580
+ assert_equal 2, first_firm.plain_clients.size
581
+ natural = first_firm.plain_clients.create(:name => "Natural Company")
582
+ assert_equal 3, first_firm.plain_clients.length
583
+ assert_equal 3, first_firm.plain_clients.size
584
+ end
424
585
 
425
586
  def test_adding_a_mismatch_class
426
587
  assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << nil }
@@ -496,6 +657,35 @@ class HasManyAssociationsTest < Test::Unit::TestCase
496
657
  assert_equal 3, companies(:first_firm).clients_of_firm(true).size
497
658
  end
498
659
 
660
+ def test_build_without_loading_association
661
+ first_topic = topics(:first)
662
+ Reply.column_names
663
+
664
+ assert_equal 1, first_topic.replies.length
665
+
666
+ assert_no_queries do
667
+ first_topic.replies.build(:title => "Not saved", :content => "Superstars")
668
+ assert_equal 2, first_topic.replies.size
669
+ end
670
+
671
+ assert_equal 2, first_topic.replies.to_ary.size
672
+ end
673
+
674
+ def test_create_without_loading_association
675
+ first_firm = companies(:first_firm)
676
+ Firm.column_names
677
+ Client.column_names
678
+
679
+ assert_equal 1, first_firm.clients_of_firm.size
680
+ first_firm.clients_of_firm.reset
681
+
682
+ assert_queries(1) do
683
+ first_firm.clients_of_firm.create(:name => "Superstars")
684
+ end
685
+
686
+ assert_equal 2, first_firm.clients_of_firm.size
687
+ end
688
+
499
689
  def test_invalid_build
500
690
  new_client = companies(:first_firm).clients_of_firm.build
501
691
  assert new_client.new_record?
@@ -633,7 +823,7 @@ class HasManyAssociationsTest < Test::Unit::TestCase
633
823
 
634
824
  def test_deleting_a_item_which_is_not_in_the_collection
635
825
  force_signal37_to_load_all_clients_of_firm
636
- summit = Client.find_first("name = 'Summit'")
826
+ summit = Client.find_by_name('Summit')
637
827
  companies(:first_firm).clients_of_firm.delete(summit)
638
828
  assert_equal 1, companies(:first_firm).clients_of_firm.size
639
829
  assert_equal 1, companies(:first_firm).clients_of_firm(true).size
@@ -762,6 +952,10 @@ class HasManyAssociationsTest < Test::Unit::TestCase
762
952
  assert firm.clients.include?(Client.find_by_name("New Client"))
763
953
  end
764
954
 
955
+ def test_get_ids
956
+ assert_equal [companies(:first_client).id, companies(:second_client).id], companies(:first_firm).client_ids
957
+ end
958
+
765
959
  def test_assign_ids
766
960
  firm = Firm.new("name" => "Apple")
767
961
  firm.client_ids = [companies(:first_client).id, companies(:second_client).id]
@@ -770,6 +964,16 @@ class HasManyAssociationsTest < Test::Unit::TestCase
770
964
  assert_equal 2, firm.clients.length
771
965
  assert firm.clients.include?(companies(:second_client))
772
966
  end
967
+
968
+ def test_assign_ids_ignoring_blanks
969
+ firm = Firm.new("name" => "Apple")
970
+ firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, '']
971
+ firm.save
972
+ firm.reload
973
+ assert_equal 2, firm.clients.length
974
+ assert firm.clients.include?(companies(:second_client))
975
+ end
976
+
773
977
  end
774
978
 
775
979
  class BelongsToAssociationsTest < Test::Unit::TestCase
@@ -1200,7 +1404,9 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
1200
1404
  def test_adding_uses_explicit_values_on_join_table
1201
1405
  ac = projects(:action_controller)
1202
1406
  assert !developers(:jamis).projects.include?(ac)
1203
- developers(:jamis).projects.push_with_attributes(ac, :access_level => 3)
1407
+ assert_deprecated do
1408
+ developers(:jamis).projects.push_with_attributes(ac, :access_level => 3)
1409
+ end
1204
1410
 
1205
1411
  assert developers(:jamis, :reload).projects.include?(ac)
1206
1412
  project = developers(:jamis).projects.detect { |p| p == ac }
@@ -1243,9 +1449,13 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
1243
1449
  no_of_projects = Project.count
1244
1450
  now = Date.today
1245
1451
  ken = Developer.new("name" => "Ken")
1246
- ken.projects.push_with_attributes( Project.find(1), :joined_on => now )
1452
+ assert_deprecated do
1453
+ ken.projects.push_with_attributes( Project.find(1), :joined_on => now )
1454
+ end
1247
1455
  p = Project.new("name" => "Foomatic")
1248
- ken.projects.push_with_attributes( p, :joined_on => now )
1456
+ assert_deprecated do
1457
+ ken.projects.push_with_attributes( p, :joined_on => now )
1458
+ end
1249
1459
  assert ken.new_record?
1250
1460
  assert p.new_record?
1251
1461
  assert ken.save
@@ -1262,17 +1472,20 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
1262
1472
  def test_habtm_saving_multiple_relationships
1263
1473
  new_project = Project.new("name" => "Grimetime")
1264
1474
  amount_of_developers = 4
1265
- developers = (0..amount_of_developers).collect {|i| Developer.create(:name => "JME #{i}") }
1266
-
1475
+ developers = (0...amount_of_developers).collect {|i| Developer.create(:name => "JME #{i}") }.reverse
1476
+
1267
1477
  new_project.developer_ids = [developers[0].id, developers[1].id]
1268
1478
  new_project.developers_with_callback_ids = [developers[2].id, developers[3].id]
1269
1479
  assert new_project.save
1270
-
1480
+
1271
1481
  new_project.reload
1272
1482
  assert_equal amount_of_developers, new_project.developers.size
1273
- amount_of_developers.times do |i|
1274
- assert_equal developers[i].name, new_project.developers[i].name
1275
- end
1483
+ assert_equal developers, new_project.developers
1484
+ end
1485
+
1486
+ def test_habtm_unique_order_preserved
1487
+ assert_equal [developers(:poor_jamis), developers(:jamis), developers(:david)], projects(:active_record).non_unique_developers
1488
+ assert_equal [developers(:poor_jamis), developers(:jamis), developers(:david)], projects(:active_record).developers
1276
1489
  end
1277
1490
 
1278
1491
  def test_build
@@ -1283,6 +1496,20 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
1283
1496
  devel.save
1284
1497
  assert !proj.new_record?
1285
1498
  assert_equal devel.projects.last, proj
1499
+ assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
1500
+ end
1501
+
1502
+ def test_build_by_new_record
1503
+ devel = Developer.new(:name => "Marcel", :salary => 75000)
1504
+ proj1 = devel.projects.build(:name => "Make bed")
1505
+ proj2 = devel.projects.build(:name => "Lie in it")
1506
+ assert_equal devel.projects.last, proj2
1507
+ assert proj2.new_record?
1508
+ devel.save
1509
+ assert !devel.new_record?
1510
+ assert !proj2.new_record?
1511
+ assert_equal devel.projects.last, proj2
1512
+ assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
1286
1513
  end
1287
1514
 
1288
1515
  def test_create
@@ -1290,6 +1517,20 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
1290
1517
  proj = devel.projects.create("name" => "Projekt")
1291
1518
  assert_equal devel.projects.last, proj
1292
1519
  assert !proj.new_record?
1520
+ assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
1521
+ end
1522
+
1523
+ def test_create_by_new_record
1524
+ devel = Developer.new(:name => "Marcel", :salary => 75000)
1525
+ proj1 = devel.projects.create(:name => "Make bed")
1526
+ proj2 = devel.projects.create(:name => "Lie in it")
1527
+ assert_equal devel.projects.last, proj2
1528
+ assert proj2.new_record?
1529
+ devel.save
1530
+ assert !devel.new_record?
1531
+ assert !proj2.new_record?
1532
+ assert_equal devel.projects.last, proj2
1533
+ assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
1293
1534
  end
1294
1535
 
1295
1536
  def test_uniq_after_the_fact
@@ -1377,8 +1618,10 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
1377
1618
 
1378
1619
  def test_rich_association
1379
1620
  jamis = developers(:jamis)
1380
- jamis.projects.push_with_attributes(projects(:action_controller), :joined_on => Date.today)
1381
-
1621
+ assert_deprecated 'push_with_attributes' do
1622
+ jamis.projects.push_with_attributes(projects(:action_controller), :joined_on => Date.today)
1623
+ end
1624
+
1382
1625
  assert_date_from_db Date.today, jamis.projects.select { |p| p.name == projects(:action_controller).name }.first.joined_on
1383
1626
  assert_date_from_db Date.today, developers(:jamis).projects.select { |p| p.name == projects(:action_controller).name }.first.joined_on
1384
1627
  end
@@ -1386,8 +1629,10 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
1386
1629
  def test_associations_with_conditions
1387
1630
  assert_equal 3, projects(:active_record).developers.size
1388
1631
  assert_equal 1, projects(:active_record).developers_named_david.size
1632
+ assert_equal 1, projects(:active_record).developers_named_david_with_hash_conditions.size
1389
1633
 
1390
1634
  assert_equal developers(:david), projects(:active_record).developers_named_david.find(developers(:david).id)
1635
+ assert_equal developers(:david), projects(:active_record).developers_named_david_with_hash_conditions.find(developers(:david).id)
1391
1636
  assert_equal developers(:david), projects(:active_record).salaried_developers.find(developers(:david).id)
1392
1637
 
1393
1638
  projects(:active_record).developers_named_david.clear
@@ -1512,4 +1757,53 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
1512
1757
  def test_join_table_alias
1513
1758
  assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL').size
1514
1759
  end
1760
+
1761
+ def test_join_with_group
1762
+ group = Developer.columns.inject([]) do |g, c|
1763
+ g << "developers.#{c.name}"
1764
+ g << "developers_projects_2.#{c.name}"
1765
+ end
1766
+ Project.columns.each { |c| group << "projects.#{c.name}" }
1767
+
1768
+ assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL', :group => group.join(",")).size
1769
+ end
1770
+
1771
+ def test_get_ids
1772
+ assert_equal [projects(:active_record).id, projects(:action_controller).id], developers(:david).project_ids
1773
+ assert_equal [projects(:active_record).id], developers(:jamis).project_ids
1774
+ end
1775
+
1776
+ def test_assign_ids
1777
+ developer = Developer.new("name" => "Joe")
1778
+ developer.project_ids = [projects(:active_record).id, projects(:action_controller).id]
1779
+ developer.save
1780
+ developer.reload
1781
+ assert_equal 2, developer.projects.length
1782
+ assert_equal projects(:active_record), developer.projects[0]
1783
+ assert_equal projects(:action_controller), developer.projects[1]
1784
+ end
1785
+
1786
+ def test_assign_ids_ignoring_blanks
1787
+ developer = Developer.new("name" => "Joe")
1788
+ developer.project_ids = [projects(:active_record).id, nil, projects(:action_controller).id, '']
1789
+ developer.save
1790
+ developer.reload
1791
+ assert_equal 2, developer.projects.length
1792
+ assert_equal projects(:active_record), developer.projects[0]
1793
+ assert_equal projects(:action_controller), developer.projects[1]
1794
+ end
1795
+
1796
+ def test_select_limited_ids_list
1797
+ # Set timestamps
1798
+ Developer.transaction do
1799
+ Developer.find(:all, :order => 'id').each_with_index do |record, i|
1800
+ record.update_attributes(:created_at => 5.years.ago + (i * 5.minutes))
1801
+ end
1802
+ end
1803
+
1804
+ join_base = ActiveRecord::Associations::ClassMethods::JoinDependency::JoinBase.new(Project)
1805
+ join_dep = ActiveRecord::Associations::ClassMethods::JoinDependency.new(join_base, :developers, nil)
1806
+ projects = Project.send(:select_limited_ids_list, {:order => 'developers.created_at'}, join_dep)
1807
+ assert_equal %w(1 2), projects.scan(/\d/).sort
1808
+ end
1515
1809
  end