activerecord 2.1.2 → 2.2.2

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 (110) hide show
  1. data/CHANGELOG +32 -6
  2. data/README +0 -0
  3. data/Rakefile +4 -5
  4. data/lib/active_record.rb +11 -10
  5. data/lib/active_record/aggregations.rb +110 -38
  6. data/lib/active_record/association_preload.rb +104 -15
  7. data/lib/active_record/associations.rb +427 -212
  8. data/lib/active_record/associations/association_collection.rb +101 -16
  9. data/lib/active_record/associations/association_proxy.rb +65 -13
  10. data/lib/active_record/associations/belongs_to_association.rb +2 -2
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -0
  12. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +13 -3
  13. data/lib/active_record/associations/has_many_association.rb +28 -28
  14. data/lib/active_record/associations/has_many_through_association.rb +21 -19
  15. data/lib/active_record/associations/has_one_association.rb +24 -7
  16. data/lib/active_record/associations/has_one_through_association.rb +3 -4
  17. data/lib/active_record/attribute_methods.rb +13 -5
  18. data/lib/active_record/base.rb +435 -212
  19. data/lib/active_record/calculations.rb +12 -5
  20. data/lib/active_record/callbacks.rb +28 -9
  21. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +355 -0
  22. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +42 -215
  23. data/lib/active_record/connection_adapters/abstract/database_statements.rb +30 -5
  24. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -1
  25. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +48 -7
  26. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +10 -4
  27. data/lib/active_record/connection_adapters/abstract_adapter.rb +67 -26
  28. data/lib/active_record/connection_adapters/mysql_adapter.rb +71 -45
  29. data/lib/active_record/connection_adapters/postgresql_adapter.rb +155 -84
  30. data/lib/active_record/dirty.rb +25 -7
  31. data/lib/active_record/dynamic_finder_match.rb +41 -0
  32. data/lib/active_record/fixtures.rb +10 -9
  33. data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
  34. data/lib/active_record/locale/en.yml +54 -0
  35. data/lib/active_record/migration.rb +47 -10
  36. data/lib/active_record/named_scope.rb +29 -16
  37. data/lib/active_record/reflection.rb +118 -54
  38. data/lib/active_record/schema_dumper.rb +13 -7
  39. data/lib/active_record/test_case.rb +18 -5
  40. data/lib/active_record/transactions.rb +89 -34
  41. data/lib/active_record/validations.rb +270 -180
  42. data/lib/active_record/version.rb +1 -1
  43. data/test/cases/active_schema_test_mysql.rb +5 -0
  44. data/test/cases/adapter_test.rb +6 -0
  45. data/test/cases/aggregations_test.rb +39 -0
  46. data/test/cases/associations/belongs_to_associations_test.rb +10 -0
  47. data/test/cases/associations/eager_load_nested_include_test.rb +30 -12
  48. data/test/cases/associations/eager_test.rb +54 -5
  49. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +77 -10
  50. data/test/cases/associations/has_many_associations_test.rb +74 -7
  51. data/test/cases/associations/has_many_through_associations_test.rb +50 -3
  52. data/test/cases/associations/has_one_associations_test.rb +17 -0
  53. data/test/cases/associations/has_one_through_associations_test.rb +49 -1
  54. data/test/cases/associations_test.rb +0 -0
  55. data/test/cases/attribute_methods_test.rb +59 -4
  56. data/test/cases/base_test.rb +93 -21
  57. data/test/cases/binary_test.rb +1 -5
  58. data/test/cases/calculations_test.rb +5 -0
  59. data/test/cases/callbacks_observers_test.rb +38 -0
  60. data/test/cases/connection_test_mysql.rb +1 -1
  61. data/test/cases/defaults_test.rb +32 -1
  62. data/test/cases/deprecated_finder_test.rb +0 -0
  63. data/test/cases/dirty_test.rb +13 -0
  64. data/test/cases/finder_test.rb +162 -12
  65. data/test/cases/fixtures_test.rb +32 -3
  66. data/test/cases/helper.rb +15 -0
  67. data/test/cases/i18n_test.rb +41 -0
  68. data/test/cases/inheritance_test.rb +2 -2
  69. data/test/cases/lifecycle_test.rb +0 -0
  70. data/test/cases/locking_test.rb +4 -9
  71. data/test/cases/method_scoping_test.rb +109 -2
  72. data/test/cases/migration_test.rb +43 -8
  73. data/test/cases/multiple_db_test.rb +25 -0
  74. data/test/cases/named_scope_test.rb +74 -0
  75. data/test/cases/pooled_connections_test.rb +103 -0
  76. data/test/cases/readonly_test.rb +0 -0
  77. data/test/cases/reflection_test.rb +11 -3
  78. data/test/cases/reload_models_test.rb +20 -0
  79. data/test/cases/sanitize_test.rb +25 -0
  80. data/test/cases/schema_authorization_test_postgresql.rb +2 -2
  81. data/test/cases/transactions_test.rb +62 -12
  82. data/test/cases/unconnected_test.rb +0 -0
  83. data/test/cases/validations_i18n_test.rb +921 -0
  84. data/test/cases/validations_test.rb +44 -33
  85. data/test/connections/native_mysql/connection.rb +1 -3
  86. data/test/fixtures/companies.yml +1 -0
  87. data/test/fixtures/customers.yml +10 -1
  88. data/test/fixtures/fixture_database.sqlite3 +0 -0
  89. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  90. data/test/fixtures/organizations.yml +5 -0
  91. data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
  92. data/test/models/author.rb +3 -0
  93. data/test/models/category.rb +3 -0
  94. data/test/models/club.rb +6 -0
  95. data/test/models/company.rb +25 -1
  96. data/test/models/customer.rb +19 -1
  97. data/test/models/member.rb +2 -0
  98. data/test/models/member_detail.rb +4 -0
  99. data/test/models/organization.rb +4 -0
  100. data/test/models/parrot.rb +1 -0
  101. data/test/models/post.rb +3 -0
  102. data/test/models/reply.rb +0 -0
  103. data/test/models/topic.rb +3 -0
  104. data/test/schema/schema.rb +12 -1
  105. metadata +22 -10
  106. data/lib/active_record/vendor/mysql.rb +0 -1214
  107. data/test/cases/adapter_test_sqlserver.rb +0 -95
  108. data/test/cases/table_name_test_sqlserver.rb +0 -23
  109. data/test/cases/threaded_connections_test.rb +0 -48
  110. data/test/schema/sqlserver_specific_schema.rb +0 -5
@@ -1,13 +1,9 @@
1
1
  require "cases/helper"
2
2
 
3
- # Without using prepared statements, it makes no sense to test
4
- # BLOB data with SQL Server, because the length of a statement is
5
- # limited to 8KB.
6
- #
7
3
  # Without using prepared statements, it makes no sense to test
8
4
  # BLOB data with DB2 or Firebird, because the length of a statement
9
5
  # is limited to 32KB.
10
- unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :DB2Adapter, :FirebirdAdapter)
6
+ unless current_adapter?(:SybaseAdapter, :DB2Adapter, :FirebirdAdapter)
11
7
  require 'models/binary'
12
8
 
13
9
  class BinaryTest < ActiveRecord::TestCase
@@ -25,6 +25,11 @@ class CalculationsTest < ActiveRecord::TestCase
25
25
  def test_should_return_nil_as_average
26
26
  assert_nil NumericData.average(:bank_balance)
27
27
  end
28
+
29
+ def test_type_cast_calculated_value_should_convert_db_averages_of_fixnum_class_to_decimal
30
+ assert_equal 0, NumericData.send(:type_cast_calculated_value, 0, nil, 'avg')
31
+ assert_equal 53.0, NumericData.send(:type_cast_calculated_value, 53, nil, 'avg')
32
+ end
28
33
 
29
34
  def test_should_get_maximum_of_field
30
35
  assert_equal 60, Account.maximum(:credit_limit)
@@ -0,0 +1,38 @@
1
+ require "cases/helper"
2
+
3
+ class Comment < ActiveRecord::Base
4
+ attr_accessor :callers
5
+
6
+ before_validation :record_callers
7
+
8
+ def after_validation
9
+ record_callers
10
+ end
11
+
12
+ def record_callers
13
+ callers << self.class if callers
14
+ end
15
+ end
16
+
17
+ class CommentObserver < ActiveRecord::Observer
18
+ attr_accessor :callers
19
+
20
+ def after_validation(model)
21
+ callers << self.class if callers
22
+ end
23
+ end
24
+
25
+ class CallbacksObserversTest < ActiveRecord::TestCase
26
+ def test_model_callbacks_fire_before_observers_are_notified
27
+ callers = []
28
+
29
+ comment = Comment.new
30
+ comment.callers = callers
31
+
32
+ CommentObserver.instance.callers = callers
33
+
34
+ comment.valid?
35
+
36
+ assert_equal [Comment, Comment, CommentObserver], callers, "model callbacks did not fire before observers were notified"
37
+ end
38
+ end
@@ -24,7 +24,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase
24
24
  assert @connection.active?
25
25
  @connection.update('set @@wait_timeout=1')
26
26
  sleep 2
27
- @connection.verify!(0)
27
+ @connection.verify!
28
28
  assert @connection.active?
29
29
  end
30
30
  end
@@ -19,6 +19,37 @@ class DefaultTest < ActiveRecord::TestCase
19
19
  end
20
20
 
21
21
  if current_adapter?(:MysqlAdapter)
22
+
23
+ #MySQL 5 and higher is quirky with not null text/blob columns.
24
+ #With MySQL Text/blob columns cannot have defaults. If the column is not null MySQL will report that the column has a null default
25
+ #but it behaves as though the column had a default of ''
26
+ def test_mysql_text_not_null_defaults
27
+ klass = Class.new(ActiveRecord::Base)
28
+ klass.table_name = 'test_mysql_text_not_null_defaults'
29
+ klass.connection.create_table klass.table_name do |t|
30
+ t.column :non_null_text, :text, :null => false
31
+ t.column :non_null_blob, :blob, :null => false
32
+ t.column :null_text, :text, :null => true
33
+ t.column :null_blob, :blob, :null => true
34
+ end
35
+ assert_equal '', klass.columns_hash['non_null_blob'].default
36
+ assert_equal '', klass.columns_hash['non_null_text'].default
37
+
38
+ assert_equal nil, klass.columns_hash['null_blob'].default
39
+ assert_equal nil, klass.columns_hash['null_text'].default
40
+
41
+ assert_nothing_raised do
42
+ instance = klass.create!
43
+ assert_equal '', instance.non_null_text
44
+ assert_equal '', instance.non_null_blob
45
+ assert_nil instance.null_text
46
+ assert_nil instance.null_blob
47
+ end
48
+ ensure
49
+ klass.connection.drop_table(klass.table_name) rescue nil
50
+ end
51
+
52
+
22
53
  # MySQL uses an implicit default 0 rather than NULL unless in strict mode.
23
54
  # We use an implicit NULL so schema.rb is compatible with other databases.
24
55
  def test_mysql_integer_not_null_defaults
@@ -47,7 +78,7 @@ class DefaultTest < ActiveRecord::TestCase
47
78
  end
48
79
  end
49
80
 
50
- if current_adapter?(:PostgreSQLAdapter, :SQLServerAdapter, :FirebirdAdapter, :OpenBaseAdapter, :OracleAdapter)
81
+ if current_adapter?(:PostgreSQLAdapter, :FirebirdAdapter, :OpenBaseAdapter, :OracleAdapter)
51
82
  def test_default_integers
52
83
  default = Default.new
53
84
  assert_instance_of Fixnum, default.positive_integer
File without changes
@@ -45,6 +45,19 @@ class DirtyTest < ActiveRecord::TestCase
45
45
  assert_nil pirate.catchphrase_change
46
46
  end
47
47
 
48
+ def test_aliased_attribute_changes
49
+ # the actual attribute here is name, title is an
50
+ # alias setup via alias_attribute
51
+ parrot = Parrot.new
52
+ assert !parrot.title_changed?
53
+ assert_nil parrot.title_change
54
+
55
+ parrot.name = 'Sam'
56
+ assert parrot.title_changed?
57
+ assert_nil parrot.title_was
58
+ assert_equal parrot.name_change, parrot.title_change
59
+ end
60
+
48
61
  def test_nullable_integer_not_marked_as_changed_if_new_value_is_blank
49
62
  pirate = Pirate.new
50
63
 
@@ -12,6 +12,57 @@ require 'models/customer'
12
12
  require 'models/job'
13
13
  require 'models/categorization'
14
14
 
15
+ class DynamicFinderMatchTest < ActiveRecord::TestCase
16
+ def test_find_no_match
17
+ assert_nil ActiveRecord::DynamicFinderMatch.match("not_a_finder")
18
+ end
19
+
20
+ def test_find_by
21
+ match = ActiveRecord::DynamicFinderMatch.match("find_by_age_and_sex_and_location")
22
+ assert_not_nil match
23
+ assert match.finder?
24
+ assert_equal :first, match.finder
25
+ assert_equal %w(age sex location), match.attribute_names
26
+ end
27
+
28
+ def find_by_bang
29
+ match = ActiveRecord::DynamicFinderMatch.match("find_by_age_and_sex_and_location!")
30
+ assert_not_nil match
31
+ assert match.finder?
32
+ assert match.bang?
33
+ assert_equal :first, match.finder
34
+ assert_equal %w(age sex location), match.attribute_names
35
+ end
36
+
37
+ def test_find_all_by
38
+ match = ActiveRecord::DynamicFinderMatch.match("find_all_by_age_and_sex_and_location")
39
+ assert_not_nil match
40
+ assert match.finder?
41
+ assert_equal :all, match.finder
42
+ assert_equal %w(age sex location), match.attribute_names
43
+ end
44
+
45
+ def test_find_or_initialize_by
46
+ match = ActiveRecord::DynamicFinderMatch.match("find_or_initialize_by_age_and_sex_and_location")
47
+ assert_not_nil match
48
+ assert !match.finder?
49
+ assert match.instantiator?
50
+ assert_equal :first, match.finder
51
+ assert_equal :new, match.instantiator
52
+ assert_equal %w(age sex location), match.attribute_names
53
+ end
54
+
55
+ def test_find_or_create_by
56
+ match = ActiveRecord::DynamicFinderMatch.match("find_or_create_by_age_and_sex_and_location")
57
+ assert_not_nil match
58
+ assert !match.finder?
59
+ assert match.instantiator?
60
+ assert_equal :first, match.finder
61
+ assert_equal :create, match.instantiator
62
+ assert_equal %w(age sex location), match.attribute_names
63
+ end
64
+ end
65
+
15
66
  class FinderTest < ActiveRecord::TestCase
16
67
  fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers
17
68
 
@@ -118,6 +169,12 @@ class FinderTest < ActiveRecord::TestCase
118
169
  assert_equal("fixture_3", developers.first.name)
119
170
  end
120
171
 
172
+ def test_find_with_group
173
+ developers = Developer.find(:all, :group => "salary", :select => "salary")
174
+ assert_equal 4, developers.size
175
+ assert_equal 4, developers.map(&:salary).uniq.size
176
+ end
177
+
121
178
  def test_find_with_entire_select_statement
122
179
  topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
123
180
 
@@ -146,11 +203,11 @@ class FinderTest < ActiveRecord::TestCase
146
203
  first = Topic.find(:first, :conditions => "title = 'The First Topic!'")
147
204
  assert_nil(first)
148
205
  end
149
-
206
+
150
207
  def test_first
151
208
  assert_equal topics(:second).title, Topic.first(:conditions => "title = 'The Second Topic of the day'").title
152
209
  end
153
-
210
+
154
211
  def test_first_failing
155
212
  assert_nil Topic.first(:conditions => "title = 'The Second Topic of the day!'")
156
213
  end
@@ -200,6 +257,23 @@ class FinderTest < ActiveRecord::TestCase
200
257
  assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { 'topics.approved' => true }) }
201
258
  end
202
259
 
260
+ def test_find_on_hash_conditions_with_hashed_table_name
261
+ assert Topic.find(1, :conditions => {:topics => { :approved => false }})
262
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => {:topics => { :approved => true }}) }
263
+ end
264
+
265
+ def test_find_with_hash_conditions_on_joined_table
266
+ firms = Firm.all :joins => :account, :conditions => {:accounts => { :credit_limit => 50 }}
267
+ assert_equal 1, firms.size
268
+ assert_equal companies(:first_firm), firms.first
269
+ end
270
+
271
+ def test_find_with_hash_conditions_on_joined_table_and_with_range
272
+ firms = DependentFirm.all :joins => :account, :conditions => {:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}
273
+ assert_equal 1, firms.size
274
+ assert_equal companies(:rails_core), firms.first
275
+ end
276
+
203
277
  def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
204
278
  david = customers(:david)
205
279
  assert Customer.find(david.id, :conditions => { 'customers.name' => david.name, :address => david.address })
@@ -229,7 +303,6 @@ class FinderTest < ActiveRecord::TestCase
229
303
  assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
230
304
  end
231
305
 
232
-
233
306
  def test_condition_interpolation
234
307
  assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
235
308
  assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
@@ -324,7 +397,7 @@ class FinderTest < ActiveRecord::TestCase
324
397
  Company.find(:first, :conditions => ["id=? AND name = ?", 2])
325
398
  }
326
399
  assert_raises(ActiveRecord::PreparedStatementInvalid) {
327
- Company.find(:first, :conditions => ["id=?", 2, 3, 4])
400
+ Company.find(:first, :conditions => ["id=?", 2, 3, 4])
328
401
  }
329
402
  end
330
403
 
@@ -350,7 +423,7 @@ class FinderTest < ActiveRecord::TestCase
350
423
  def test_named_bind_variables
351
424
  assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
352
425
  assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode
353
-
426
+
354
427
  assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
355
428
 
356
429
  assert_kind_of Firm, Company.find(:first, :conditions => ["name = :name", { :name => "37signals" }])
@@ -387,12 +460,13 @@ class FinderTest < ActiveRecord::TestCase
387
460
  assert_equal ActiveRecord::Base.connection.quote(''), bind('?', '')
388
461
  end
389
462
 
390
- def test_bind_string_with_nl
391
- assert_equal ActiveRecord::Base.connection.quote("a\nb"), bind('?', "a\nb")
392
- end
393
-
394
- def test_bind_mb_string_with_nl
395
- assert_equal ActiveRecord::Base.connection.quote("a\nb"), bind('?', "a\nb".chars)
463
+ def test_bind_chars
464
+ quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
465
+ quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper")
466
+ assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi")
467
+ assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper")
468
+ assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".mb_chars)
469
+ assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".mb_chars)
396
470
  end
397
471
 
398
472
  def test_bind_record
@@ -426,11 +500,33 @@ class FinderTest < ActiveRecord::TestCase
426
500
  assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
427
501
  end
428
502
 
503
+ uses_mocha('test_dynamic_finder_should_go_through_the_find_class_method') do
504
+ def test_dynamic_finders_should_go_through_the_find_class_method
505
+ Topic.expects(:find).with(:first, :conditions => { :title => 'The First Topic!' })
506
+ Topic.find_by_title("The First Topic!")
507
+
508
+ Topic.expects(:find).with(:last, :conditions => { :title => 'The Last Topic!' })
509
+ Topic.find_last_by_title("The Last Topic!")
510
+
511
+ Topic.expects(:find).with(:all, :conditions => { :title => 'A Topic.' })
512
+ Topic.find_all_by_title("A Topic.")
513
+
514
+ Topic.expects(:find).with(:first, :conditions => { :title => 'Does not exist yet for sure!' }).times(2)
515
+ Topic.find_or_initialize_by_title('Does not exist yet for sure!')
516
+ Topic.find_or_create_by_title('Does not exist yet for sure!')
517
+ end
518
+ end
519
+
429
520
  def test_find_by_one_attribute
430
521
  assert_equal topics(:first), Topic.find_by_title("The First Topic")
431
522
  assert_nil Topic.find_by_title("The First Topic!")
432
523
  end
433
524
 
525
+ def test_find_by_one_attribute_bang
526
+ assert_equal topics(:first), Topic.find_by_title!("The First Topic")
527
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") }
528
+ end
529
+
434
530
  def test_find_by_one_attribute_caches_dynamic_finder
435
531
  # ensure this test can run independently of order
436
532
  class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }
@@ -524,6 +620,38 @@ class FinderTest < ActiveRecord::TestCase
524
620
  assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary")
525
621
  end
526
622
 
623
+ def test_find_last_by_one_attribute
624
+ assert_equal Topic.last, Topic.find_last_by_title(Topic.last.title)
625
+ assert_nil Topic.find_last_by_title("A title with no matches")
626
+ end
627
+
628
+ def test_find_last_by_one_attribute_caches_dynamic_finder
629
+ # ensure this test can run independently of order
630
+ class << Topic; self; end.send(:remove_method, :find_last_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' }
631
+ assert !Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' }
632
+ t = Topic.find_last_by_title(Topic.last.title)
633
+ assert Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' }
634
+ end
635
+
636
+ def test_find_last_by_invalid_method_syntax
637
+ assert_raises(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") }
638
+ assert_raises(NoMethodError) { Topic.find_last_by_title?("The First Topic") }
639
+ end
640
+
641
+ def test_find_last_by_one_attribute_with_several_options
642
+ assert_equal accounts(:signals37), Account.find_last_by_credit_limit(50, :order => 'id DESC', :conditions => ['id != ?', 3])
643
+ end
644
+
645
+ def test_find_last_by_one_missing_attribute
646
+ assert_raises(NoMethodError) { Topic.find_last_by_undertitle("The Last Topic!") }
647
+ end
648
+
649
+ def test_find_last_by_two_attributes
650
+ topic = Topic.last
651
+ assert_equal topic, Topic.find_last_by_title_and_author_name(topic.title, topic.author_name)
652
+ assert_nil Topic.find_last_by_title_and_author_name(topic.title, "Anonymous")
653
+ end
654
+
527
655
  def test_find_all_by_one_attribute
528
656
  topics = Topic.find_all_by_content("Have a nice day")
529
657
  assert_equal 2, topics.size
@@ -717,7 +845,18 @@ class FinderTest < ActiveRecord::TestCase
717
845
  assert c.valid?
718
846
  assert !c.new_record?
719
847
  end
720
-
848
+
849
+ def test_find_or_create_should_work_with_block_on_first_call
850
+ class << Company
851
+ undef_method(:find_or_create_by_name) if method_defined?(:find_or_create_by_name)
852
+ end
853
+ c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
854
+ assert_equal "Fortune 1000", c.name
855
+ assert_equal 1000.to_f, c.rating.to_f
856
+ assert c.valid?
857
+ assert !c.new_record?
858
+ end
859
+
721
860
  def test_dynamic_find_or_initialize_from_one_attribute_caches_method
722
861
  class << Company; self; end.send(:remove_method, :find_or_initialize_by_name) if Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
723
862
  assert !Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
@@ -824,6 +963,17 @@ class FinderTest < ActiveRecord::TestCase
824
963
  assert_equal 1, first.id
825
964
  end
826
965
 
966
+ def test_joins_with_string_array
967
+ person_with_reader_and_post = Post.find(
968
+ :all,
969
+ :joins => [
970
+ "INNER JOIN categorizations ON categorizations.post_id = posts.id",
971
+ "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
972
+ ]
973
+ )
974
+ assert_equal 1, person_with_reader_and_post.size
975
+ end
976
+
827
977
  def test_find_by_id_with_conditions_with_or
828
978
  assert_nothing_raised do
829
979
  Post.find([1,2,3],
@@ -15,6 +15,7 @@ require 'models/pirate'
15
15
  require 'models/treasure'
16
16
  require 'models/matey'
17
17
  require 'models/ship'
18
+ require 'models/book'
18
19
 
19
20
  class FixturesTest < ActiveRecord::TestCase
20
21
  self.use_instantiated_fixtures = true
@@ -373,6 +374,34 @@ class CheckSetTableNameFixturesTest < ActiveRecord::TestCase
373
374
  end
374
375
  end
375
376
 
377
+ class FixtureNameIsNotTableNameFixturesTest < ActiveRecord::TestCase
378
+ set_fixture_class :items => Book
379
+ fixtures :items
380
+ # Set to false to blow away fixtures cache and ensure our fixtures are loaded
381
+ # and thus takes into account our set_fixture_class
382
+ self.use_transactional_fixtures = false
383
+
384
+ def test_named_accessor
385
+ assert_kind_of Book, items(:dvd)
386
+ end
387
+ end
388
+
389
+ class FixtureNameIsNotTableNameMultipleFixturesTest < ActiveRecord::TestCase
390
+ set_fixture_class :items => Book, :funny_jokes => Joke
391
+ fixtures :items, :funny_jokes
392
+ # Set to false to blow away fixtures cache and ensure our fixtures are loaded
393
+ # and thus takes into account our set_fixture_class
394
+ self.use_transactional_fixtures = false
395
+
396
+ def test_named_accessor_of_differently_named_fixture
397
+ assert_kind_of Book, items(:dvd)
398
+ end
399
+
400
+ def test_named_accessor_of_same_named_fixture
401
+ assert_kind_of Joke, funny_jokes(:a_joke)
402
+ end
403
+ end
404
+
376
405
  class CustomConnectionFixturesTest < ActiveRecord::TestCase
377
406
  set_fixture_class :courses => Course
378
407
  fixtures :courses
@@ -432,11 +461,11 @@ class FixturesBrokenRollbackTest < ActiveRecord::TestCase
432
461
  alias_method :teardown, :blank_teardown
433
462
 
434
463
  def test_no_rollback_in_teardown_unless_transaction_active
435
- assert_equal 0, Thread.current['open_transactions']
464
+ assert_equal 0, ActiveRecord::Base.connection.open_transactions
436
465
  assert_raise(RuntimeError) { ar_setup_fixtures }
437
- assert_equal 0, Thread.current['open_transactions']
466
+ assert_equal 0, ActiveRecord::Base.connection.open_transactions
438
467
  assert_nothing_raised { ar_teardown_fixtures }
439
- assert_equal 0, Thread.current['open_transactions']
468
+ assert_equal 0, ActiveRecord::Base.connection.open_transactions
440
469
  end
441
470
 
442
471
  private