activerecord 1.13.2 → 1.14.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 (144) hide show
  1. data/CHANGELOG +452 -10
  2. data/RUNNING_UNIT_TESTS +1 -1
  3. data/lib/active_record.rb +5 -2
  4. data/lib/active_record/acts/list.rb +1 -1
  5. data/lib/active_record/acts/tree.rb +29 -25
  6. data/lib/active_record/aggregations.rb +3 -2
  7. data/lib/active_record/associations.rb +783 -337
  8. data/lib/active_record/associations/association_collection.rb +7 -12
  9. data/lib/active_record/associations/association_proxy.rb +62 -24
  10. data/lib/active_record/associations/belongs_to_association.rb +27 -46
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  12. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +38 -38
  13. data/lib/active_record/associations/has_many_association.rb +61 -56
  14. data/lib/active_record/associations/has_many_through_association.rb +144 -0
  15. data/lib/active_record/associations/has_one_association.rb +22 -16
  16. data/lib/active_record/base.rb +482 -182
  17. data/lib/active_record/calculations.rb +225 -0
  18. data/lib/active_record/callbacks.rb +7 -7
  19. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +162 -47
  20. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  21. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -1
  22. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +21 -1
  23. data/lib/active_record/connection_adapters/abstract_adapter.rb +34 -2
  24. data/lib/active_record/connection_adapters/db2_adapter.rb +107 -61
  25. data/lib/active_record/connection_adapters/mysql_adapter.rb +29 -6
  26. data/lib/active_record/connection_adapters/openbase_adapter.rb +349 -0
  27. data/lib/active_record/connection_adapters/{oci_adapter.rb → oracle_adapter.rb} +125 -59
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +24 -21
  29. data/lib/active_record/connection_adapters/sqlite_adapter.rb +47 -8
  30. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +36 -16
  31. data/lib/active_record/connection_adapters/sybase_adapter.rb +684 -0
  32. data/lib/active_record/fixtures.rb +42 -17
  33. data/lib/active_record/locking.rb +36 -15
  34. data/lib/active_record/migration.rb +111 -8
  35. data/lib/active_record/observer.rb +25 -1
  36. data/lib/active_record/reflection.rb +103 -41
  37. data/lib/active_record/schema.rb +2 -2
  38. data/lib/active_record/schema_dumper.rb +55 -18
  39. data/lib/active_record/timestamp.rb +6 -6
  40. data/lib/active_record/validations.rb +65 -40
  41. data/lib/active_record/vendor/db2.rb +10 -5
  42. data/lib/active_record/vendor/simple.rb +693 -702
  43. data/lib/active_record/version.rb +2 -2
  44. data/rakefile +4 -4
  45. data/test/aaa_create_tables_test.rb +25 -6
  46. data/test/abstract_unit.rb +39 -1
  47. data/test/adapter_test.rb +31 -4
  48. data/test/associations_cascaded_eager_loading_test.rb +106 -0
  49. data/test/associations_go_eager_test.rb +85 -16
  50. data/test/associations_join_model_test.rb +338 -0
  51. data/test/associations_test.rb +129 -50
  52. data/test/base_test.rb +204 -49
  53. data/test/binary_test.rb +1 -1
  54. data/test/calculations_test.rb +169 -0
  55. data/test/callbacks_test.rb +5 -23
  56. data/test/class_inheritable_attributes_test.rb +1 -1
  57. data/test/column_alias_test.rb +1 -1
  58. data/test/connections/native_mysql/connection.rb +1 -0
  59. data/test/connections/native_openbase/connection.rb +22 -0
  60. data/test/connections/{native_oci → native_oracle}/connection.rb +7 -9
  61. data/test/connections/native_sqlite/connection.rb +1 -1
  62. data/test/connections/native_sqlite3/connection.rb +1 -0
  63. data/test/connections/native_sqlite3/in_memory_connection.rb +1 -0
  64. data/test/connections/native_sybase/connection.rb +24 -0
  65. data/test/defaults_test.rb +18 -0
  66. data/test/deprecated_associations_test.rb +2 -2
  67. data/test/deprecated_finder_test.rb +0 -6
  68. data/test/finder_test.rb +26 -23
  69. data/test/fixtures/accounts.yml +10 -0
  70. data/test/fixtures/author.rb +31 -6
  71. data/test/fixtures/author_favorites.yml +4 -0
  72. data/test/fixtures/categories/special_categories.yml +9 -0
  73. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  74. data/test/fixtures/categories_posts.yml +4 -0
  75. data/test/fixtures/categorization.rb +5 -0
  76. data/test/fixtures/categorizations.yml +11 -0
  77. data/test/fixtures/category.rb +6 -0
  78. data/test/fixtures/company.rb +17 -5
  79. data/test/fixtures/company_in_module.rb +19 -5
  80. data/test/fixtures/db_definitions/db2.drop.sql +3 -0
  81. data/test/fixtures/db_definitions/db2.sql +121 -100
  82. data/test/fixtures/db_definitions/db22.sql +2 -2
  83. data/test/fixtures/db_definitions/firebird.drop.sql +4 -0
  84. data/test/fixtures/db_definitions/firebird.sql +26 -0
  85. data/test/fixtures/db_definitions/mysql.drop.sql +3 -0
  86. data/test/fixtures/db_definitions/mysql.sql +21 -1
  87. data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
  88. data/test/fixtures/db_definitions/openbase.sql +282 -0
  89. data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
  90. data/test/fixtures/db_definitions/openbase2.sql +7 -0
  91. data/test/fixtures/db_definitions/{oci.drop.sql → oracle.drop.sql} +6 -0
  92. data/test/fixtures/db_definitions/{oci.sql → oracle.sql} +25 -4
  93. data/test/fixtures/db_definitions/{oci2.drop.sql → oracle2.drop.sql} +0 -0
  94. data/test/fixtures/db_definitions/{oci2.sql → oracle2.sql} +0 -0
  95. data/test/fixtures/db_definitions/postgresql.drop.sql +4 -0
  96. data/test/fixtures/db_definitions/postgresql.sql +22 -1
  97. data/test/fixtures/db_definitions/schema.rb +32 -0
  98. data/test/fixtures/db_definitions/sqlite.drop.sql +3 -0
  99. data/test/fixtures/db_definitions/sqlite.sql +18 -0
  100. data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
  101. data/test/fixtures/db_definitions/sqlserver.sql +23 -3
  102. data/test/fixtures/db_definitions/sybase.drop.sql +31 -0
  103. data/test/fixtures/db_definitions/sybase.sql +204 -0
  104. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  105. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  106. data/test/fixtures/developers.yml +6 -1
  107. data/test/fixtures/developers_projects.yml +4 -0
  108. data/test/fixtures/funny_jokes.yml +14 -0
  109. data/test/fixtures/joke.rb +6 -0
  110. data/test/fixtures/legacy_thing.rb +3 -0
  111. data/test/fixtures/legacy_things.yml +3 -0
  112. data/test/fixtures/mixin.rb +1 -1
  113. data/test/fixtures/person.rb +4 -1
  114. data/test/fixtures/post.rb +26 -1
  115. data/test/fixtures/project.rb +1 -0
  116. data/test/fixtures/reader.rb +4 -0
  117. data/test/fixtures/readers.yml +4 -0
  118. data/test/fixtures/reply.rb +2 -1
  119. data/test/fixtures/tag.rb +5 -0
  120. data/test/fixtures/tagging.rb +6 -0
  121. data/test/fixtures/taggings.yml +18 -0
  122. data/test/fixtures/tags.yml +7 -0
  123. data/test/fixtures/tasks.yml +2 -2
  124. data/test/fixtures/topic.rb +2 -2
  125. data/test/fixtures/topics.yml +1 -0
  126. data/test/fixtures_test.rb +47 -13
  127. data/test/inheritance_test.rb +2 -2
  128. data/test/locking_test.rb +15 -1
  129. data/test/method_scoping_test.rb +248 -13
  130. data/test/migration_test.rb +68 -11
  131. data/test/mixin_nested_set_test.rb +1 -1
  132. data/test/modules_test.rb +6 -1
  133. data/test/readonly_test.rb +1 -1
  134. data/test/reflection_test.rb +63 -9
  135. data/test/schema_dumper_test.rb +41 -0
  136. data/test/{synonym_test_oci.rb → synonym_test_oracle.rb} +1 -1
  137. data/test/threaded_connections_test.rb +10 -0
  138. data/test/unconnected_test.rb +12 -5
  139. data/test/validations_test.rb +197 -10
  140. metadata +295 -260
  141. data/test/fixtures/db_definitions/create_oracle_db.bat +0 -0
  142. data/test/fixtures/db_definitions/create_oracle_db.sh +0 -0
  143. data/test/fixtures/fixture_database.sqlite +0 -0
  144. data/test/fixtures/fixture_database_2.sqlite +0 -0
@@ -0,0 +1,4 @@
1
+ DROP TABLE courses
2
+ go
3
+
4
+
@@ -0,0 +1,5 @@
1
+ CREATE TABLE courses (
2
+ id int NOT NULL PRIMARY KEY,
3
+ name varchar(255) NOT NULL
4
+ )
5
+ go
@@ -13,4 +13,9 @@ dev_<%= digit %>:
13
13
  id: <%= digit %>
14
14
  name: fixture_<%= digit %>
15
15
  salary: 100000
16
- <% end %>
16
+ <% end %>
17
+
18
+ poor_jamis:
19
+ id: 11
20
+ name: Jamis
21
+ salary: 9000
@@ -11,3 +11,7 @@ david_active_record:
11
11
  jamis_active_record:
12
12
  developer_id: 2
13
13
  project_id: 1
14
+
15
+ poor_jamis_active_record:
16
+ developer_id: 11
17
+ project_id: 1
@@ -0,0 +1,14 @@
1
+ a_joke:
2
+ id: 1
3
+ name: Knock knock
4
+
5
+ another_joke:
6
+ id: 2
7
+ name: The Aristocrats
8
+ a_joke:
9
+ id: 1
10
+ name: Knock knock
11
+
12
+ another_joke:
13
+ id: 2
14
+ name: The Aristocrats
@@ -0,0 +1,6 @@
1
+ class Joke < ActiveRecord::Base
2
+ set_table_name 'funny_jokes'
3
+ end
4
+ class Joke < ActiveRecord::Base
5
+ set_table_name 'funny_jokes'
6
+ end
@@ -0,0 +1,3 @@
1
+ class LegacyThing < ActiveRecord::Base
2
+ set_locking_column :version
3
+ end
@@ -0,0 +1,3 @@
1
+ obtuse:
2
+ id: 1
3
+ tps_report_number: 500
@@ -30,7 +30,7 @@ class ListWithStringScopeMixin < ActiveRecord::Base
30
30
  end
31
31
 
32
32
  class NestedSet < Mixin
33
- acts_as_nested_set :scope => "ROOT_ID IS NULL"
33
+ acts_as_nested_set :scope => "root_id IS NULL"
34
34
 
35
35
  def self.table_name() "mixins" end
36
36
  end
@@ -1 +1,4 @@
1
- class Person < ActiveRecord::Base; end
1
+ class Person < ActiveRecord::Base
2
+ has_many :readers
3
+ has_many :posts, :through => :readers
4
+ end
@@ -18,8 +18,29 @@ class Post < ActiveRecord::Base
18
18
  has_many :special_comments
19
19
 
20
20
  has_and_belongs_to_many :categories
21
- has_and_belongs_to_many :special_categories, :join_table => "categories_posts"
21
+ has_and_belongs_to_many :special_categories, :join_table => "categories_posts", :association_foreign_key => 'category_id'
22
+
23
+ has_many :taggings, :as => :taggable
24
+ has_many :tags, :through => :taggings, :include => :tagging do
25
+ def add_joins_and_select
26
+ find :all, :select => 'tags.*, authors.id as author_id', :include => false,
27
+ :joins => 'left outer join posts on taggings.taggable_id = posts.id left outer join authors on posts.author_id = authors.id'
28
+ end
29
+ end
22
30
 
31
+ has_many :funky_tags, :through => :taggings, :source => :tag
32
+ has_many :super_tags, :through => :taggings
33
+ has_one :tagging, :as => :taggable
34
+
35
+ has_many :invalid_taggings, :as => :taggable, :class_name => "Tagging", :conditions => 'taggings.id < 0'
36
+ has_many :invalid_tags, :through => :invalid_taggings, :source => :tag
37
+
38
+ has_many :categorizations, :foreign_key => :category_id
39
+ has_many :authors, :through => :categorizations
40
+
41
+ has_many :readers
42
+ has_many :people, :through => :readers
43
+
23
44
  def self.what_are_you
24
45
  'a post...'
25
46
  end
@@ -28,5 +49,9 @@ end
28
49
  class SpecialPost < Post; end;
29
50
 
30
51
  class StiPost < Post
52
+ self.abstract_class = true
31
53
  has_one :special_comment, :class_name => "SpecialComment"
32
54
  end
55
+
56
+ class SubStiPost < StiPost
57
+ end
@@ -1,5 +1,6 @@
1
1
  class Project < ActiveRecord::Base
2
2
  has_and_belongs_to_many :developers, :uniq => true
3
+ has_and_belongs_to_many :limited_developers, :class_name => "Developer", :limit => 1
3
4
  has_and_belongs_to_many :developers_named_david, :class_name => "Developer", :conditions => "name = 'David'", :uniq => true
4
5
  has_and_belongs_to_many :salaried_developers, :class_name => "Developer", :conditions => "salary > 0"
5
6
  has_and_belongs_to_many :developers_with_finder_sql, :class_name => "Developer", :finder_sql => 'SELECT t.*, j.* FROM developers_projects j, developers t WHERE t.id = j.developer_id AND j.project_id = #{id}'
@@ -0,0 +1,4 @@
1
+ class Reader < ActiveRecord::Base
2
+ belongs_to :post
3
+ belongs_to :person
4
+ end
@@ -0,0 +1,4 @@
1
+ michael_welcome:
2
+ id: 1
3
+ post_id: 1
4
+ person_id: 1
@@ -2,7 +2,7 @@ require 'fixtures/topic'
2
2
 
3
3
  class Reply < Topic
4
4
  belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true
5
- has_many :silly_replies, :dependent => true, :foreign_key => "parent_id"
5
+ has_many :replies, :class_name => "SillyReply", :dependent => :destroy, :foreign_key => "parent_id"
6
6
 
7
7
  validate :errors_on_empty_content
8
8
  validate_on_create :title_is_wrong_create
@@ -33,4 +33,5 @@ class Reply < Topic
33
33
  end
34
34
 
35
35
  class SillyReply < Reply
36
+ belongs_to :reply, :foreign_key => "parent_id", :counter_cache => :replies_count
36
37
  end
@@ -0,0 +1,5 @@
1
+ class Tag < ActiveRecord::Base
2
+ has_many :taggings, :as => :taggable
3
+ has_many :taggables, :through => :taggings
4
+ has_one :tagging, :as => :taggable
5
+ end
@@ -0,0 +1,6 @@
1
+ class Tagging < ActiveRecord::Base
2
+ belongs_to :tag, :include => :tagging
3
+ belongs_to :super_tag, :class_name => 'Tag', :foreign_key => 'super_tag_id'
4
+ belongs_to :invalid_tag, :class_name => 'Tag', :foreign_key => 'tag_id'
5
+ belongs_to :taggable, :polymorphic => true, :counter_cache => true
6
+ end
@@ -0,0 +1,18 @@
1
+ welcome_general:
2
+ id: 1
3
+ tag_id: 1
4
+ super_tag_id: 2
5
+ taggable_id: 1
6
+ taggable_type: Post
7
+
8
+ thinking_general:
9
+ id: 2
10
+ tag_id: 1
11
+ taggable_id: 2
12
+ taggable_type: Post
13
+
14
+ fake:
15
+ id: 3
16
+ tag_id: 1
17
+ taggable_id: 1
18
+ taggable_type: FakeModel
@@ -0,0 +1,7 @@
1
+ general:
2
+ id: 1
3
+ name: General
4
+
5
+ misc:
6
+ id: 2
7
+ name: Misc
@@ -1,7 +1,7 @@
1
1
  # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
2
  first_task:
3
3
  id: 1
4
- starting: "2005-03-30 06:30:00"
5
- ending: "2005-03-30 08:30:00"
4
+ starting: 2005-03-30t06:30:00.00+01:00
5
+ ending: 2005-03-30t08:30:00.00+01:00
6
6
  another_task:
7
7
  id: 2
@@ -1,12 +1,12 @@
1
1
  class Topic < ActiveRecord::Base
2
- has_many :replies, :dependent => true, :foreign_key => "parent_id"
2
+ has_many :replies, :dependent => :destroy, :foreign_key => "parent_id"
3
3
  serialize :content
4
4
 
5
5
  before_create :default_written_on
6
6
  before_destroy :destroy_children
7
7
 
8
8
  def parent
9
- self.class.find(parent_id)
9
+ Topic.find(parent_id)
10
10
  end
11
11
 
12
12
  protected
@@ -19,3 +19,4 @@ second:
19
19
  approved: true
20
20
  replies_count: 2
21
21
  parent_id: 1
22
+ type: Reply
@@ -4,12 +4,14 @@ require 'fixtures/developer'
4
4
  require 'fixtures/company'
5
5
  require 'fixtures/task'
6
6
  require 'fixtures/reply'
7
+ require 'fixtures/joke'
8
+ require 'fixtures/category'
7
9
 
8
10
  class FixturesTest < Test::Unit::TestCase
9
11
  self.use_instantiated_fixtures = true
10
12
  self.use_transactional_fixtures = false
11
13
 
12
- fixtures :topics, :developers, :accounts, :tasks
14
+ fixtures :topics, :developers, :accounts, :tasks, :categories, :funny_jokes
13
15
 
14
16
  FIXTURES = %w( accounts companies customers
15
17
  developers developers_projects entrants
@@ -60,7 +62,7 @@ class FixturesTest < Test::Unit::TestCase
60
62
  t.column :written_on, :datetime
61
63
  t.column :bonus_time, :time
62
64
  t.column :last_read, :date
63
- t.column :content, :text
65
+ t.column :content, :string
64
66
  t.column :approved, :boolean, :default => true
65
67
  t.column :replies_count, :integer, :default => 0
66
68
  t.column :parent_id, :integer
@@ -77,16 +79,16 @@ class FixturesTest < Test::Unit::TestCase
77
79
 
78
80
  topics = create_fixtures("topics")
79
81
 
80
- # Restore prefix/suffix to its previous values
81
- ActiveRecord::Base.table_name_prefix = old_prefix
82
- ActiveRecord::Base.table_name_suffix = old_suffix
83
-
84
82
  firstRow = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'David'")
85
83
  assert_equal("The First Topic", firstRow["title"])
86
84
 
87
85
  secondRow = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'Mary'")
88
86
  assert_nil(secondRow["author_email_address"])
89
87
  ensure
88
+ # Restore prefix/suffix to its previous values
89
+ ActiveRecord::Base.table_name_prefix = old_prefix
90
+ ActiveRecord::Base.table_name_suffix = old_suffix
91
+
90
92
  ActiveRecord::Base.connection.drop_table :prefix_topics_suffix rescue nil
91
93
  end
92
94
  end
@@ -110,7 +112,7 @@ class FixturesTest < Test::Unit::TestCase
110
112
 
111
113
  def test_deprecated_yaml_extension
112
114
  assert_raise(Fixture::FormatError) {
113
- Fixtures.new(nil, 'bad_extension', File.join(File.dirname(__FILE__), 'fixtures'))
115
+ Fixtures.new(nil, 'bad_extension', 'BadExtension', File.join(File.dirname(__FILE__), 'fixtures'))
114
116
  }
115
117
  end
116
118
 
@@ -136,31 +138,31 @@ class FixturesTest < Test::Unit::TestCase
136
138
  end
137
139
 
138
140
  def test_erb_in_fixtures
139
- assert_equal 10, @developers.size
141
+ assert_equal 11, @developers.size
140
142
  assert_equal "fixture_5", @dev_5.name
141
143
  end
142
144
 
143
145
  def test_empty_yaml_fixture
144
- assert_not_nil Fixtures.new( Account.connection, "accounts", File.dirname(__FILE__) + "/fixtures/naked/yml/accounts")
146
+ assert_not_nil Fixtures.new( Account.connection, "accounts", 'Account', File.dirname(__FILE__) + "/fixtures/naked/yml/accounts")
145
147
  end
146
148
 
147
149
  def test_empty_yaml_fixture_with_a_comment_in_it
148
- assert_not_nil Fixtures.new( Account.connection, "companies", File.dirname(__FILE__) + "/fixtures/naked/yml/companies")
150
+ assert_not_nil Fixtures.new( Account.connection, "companies", 'Company', File.dirname(__FILE__) + "/fixtures/naked/yml/companies")
149
151
  end
150
152
 
151
153
  def test_dirty_dirty_yaml_file
152
154
  assert_raises(Fixture::FormatError) do
153
- Fixtures.new( Account.connection, "courses", File.dirname(__FILE__) + "/fixtures/naked/yml/courses")
155
+ Fixtures.new( Account.connection, "courses", 'Course', File.dirname(__FILE__) + "/fixtures/naked/yml/courses")
154
156
  end
155
157
  end
156
158
 
157
159
  def test_empty_csv_fixtures
158
- assert_not_nil Fixtures.new( Account.connection, "accounts", File.dirname(__FILE__) + "/fixtures/naked/csv/accounts")
160
+ assert_not_nil Fixtures.new( Account.connection, "accounts", 'Account', File.dirname(__FILE__) + "/fixtures/naked/csv/accounts")
159
161
  end
160
162
 
161
163
  def test_omap_fixtures
162
164
  assert_nothing_raised do
163
- fixtures = Fixtures.new(Account.connection, 'categories', File.dirname(__FILE__) + '/fixtures/categories_ordered')
165
+ fixtures = Fixtures.new(Account.connection, 'categories', 'Category', File.dirname(__FILE__) + '/fixtures/categories_ordered')
164
166
 
165
167
  i = 0
166
168
  fixtures.each do |name, fixture|
@@ -170,6 +172,19 @@ class FixturesTest < Test::Unit::TestCase
170
172
  end
171
173
  end
172
174
  end
175
+
176
+
177
+ def test_yml_file_in_subdirectory
178
+ assert_equal(categories(:sub_special_1).name, "A special category in a subdir file")
179
+ assert_equal(categories(:sub_special_1).class, SpecialCategory)
180
+ end
181
+
182
+ def test_subsubdir_file_with_arbitrary_name
183
+ assert_equal(categories(:sub_special_3).name, "A special category in an arbitrarily named subsubdir file")
184
+ assert_equal(categories(:sub_special_3).class, SpecialCategory)
185
+ end
186
+
187
+
173
188
  end
174
189
 
175
190
  if Account.connection.respond_to?(:reset_pk_sequence!)
@@ -309,3 +324,22 @@ class ForeignKeyFixturesTest < Test::Unit::TestCase
309
324
  assert true
310
325
  end
311
326
  end
327
+
328
+ class SetTableNameFixturesTest < Test::Unit::TestCase
329
+ set_fixture_class :funny_jokes => 'Joke'
330
+ fixtures :funny_jokes
331
+
332
+ def test_table_method
333
+ assert_kind_of Joke, funny_jokes(:a_joke)
334
+ end
335
+ end
336
+
337
+ class InvalidTableNameFixturesTest < Test::Unit::TestCase
338
+ fixtures :funny_jokes
339
+
340
+ def test_raises_error
341
+ assert_raises FixtureClassNotFound do
342
+ funny_jokes(:a_joke)
343
+ end
344
+ end
345
+ end
@@ -8,13 +8,13 @@ class InheritanceTest < Test::Unit::TestCase
8
8
 
9
9
  def test_a_bad_type_column
10
10
  #SQLServer need to turn Identity Insert On before manually inserting into the Identity column
11
- if current_adapter?(:SQLServerAdapter)
11
+ if current_adapter?(:SQLServerAdapter) || current_adapter?(:SybaseAdapter)
12
12
  Company.connection.execute "SET IDENTITY_INSERT companies ON"
13
13
  end
14
14
  Company.connection.insert "INSERT INTO companies (id, #{QUOTED_TYPE}, name) VALUES(100, 'bad_class!', 'Not happening')"
15
15
 
16
16
  #We then need to turn it back Off before continuing.
17
- if current_adapter?(:SQLServerAdapter)
17
+ if current_adapter?(:SQLServerAdapter) || current_adapter?(:SybaseAdapter)
18
18
  Company.connection.execute "SET IDENTITY_INSERT companies OFF"
19
19
  end
20
20
  assert_raises(ActiveRecord::SubclassNotFound) { Company.find(100) }
@@ -1,8 +1,9 @@
1
1
  require 'abstract_unit'
2
2
  require 'fixtures/person'
3
+ require 'fixtures/legacy_thing'
3
4
 
4
5
  class LockingTest < Test::Unit::TestCase
5
- fixtures :people
6
+ fixtures :people, :legacy_things
6
7
 
7
8
  def test_lock_existing
8
9
  p1 = Person.find(1)
@@ -28,5 +29,18 @@ class LockingTest < Test::Unit::TestCase
28
29
  p2.first_name = "should fail"
29
30
  p2.save
30
31
  }
32
+ end
33
+
34
+ def test_lock_column_name_existing
35
+ t1 = LegacyThing.find(1)
36
+ t2 = LegacyThing.find(1)
37
+ t1.tps_report_number = 400
38
+ t1.save
39
+
40
+ assert_raises(ActiveRecord::StaleObjectError) {
41
+ t2.tps_report_number = 300
42
+ t2.save
43
+ }
31
44
  end
45
+
32
46
  end
@@ -1,15 +1,16 @@
1
1
  require 'abstract_unit'
2
2
  require 'fixtures/developer'
3
+ require 'fixtures/project'
3
4
  require 'fixtures/comment'
4
5
  require 'fixtures/post'
5
6
  require 'fixtures/category'
6
7
 
7
8
  class MethodScopingTest < Test::Unit::TestCase
8
- fixtures :developers, :comments, :posts
9
+ fixtures :developers, :projects, :comments, :posts
9
10
 
10
11
  def test_set_conditions
11
12
  Developer.with_scope(:find => { :conditions => 'just a test...' }) do
12
- assert_equal 'just a test...', Thread.current[:scoped_methods][Developer][:find][:conditions]
13
+ assert_equal 'just a test...', Developer.send(:current_scoped_methods)[:find][:conditions]
13
14
  end
14
15
  end
15
16
 
@@ -25,9 +26,27 @@ class MethodScopingTest < Test::Unit::TestCase
25
26
  end
26
27
  end
27
28
 
29
+ def test_scoped_find_combines_conditions
30
+ Developer.with_scope(:find => { :conditions => "salary = 9000" }) do
31
+ assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => "name = 'Jamis'")
32
+ end
33
+ end
34
+
35
+ def test_scoped_find_sanitizes_conditions
36
+ Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
37
+ assert_equal developers(:poor_jamis), Developer.find(:first)
38
+ end
39
+ end
40
+
41
+ def test_scoped_find_combines_and_sanitizes_conditions
42
+ Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
43
+ assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => ['name = ?', 'Jamis'])
44
+ end
45
+ end
46
+
28
47
  def test_scoped_find_all
29
48
  Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
30
- assert_equal [Developer.find(1)], Developer.find(:all)
49
+ assert_equal [developers(:david)], Developer.find(:all)
31
50
  end
32
51
  end
33
52
 
@@ -42,11 +61,28 @@ class MethodScopingTest < Test::Unit::TestCase
42
61
  end
43
62
  end
44
63
 
64
+ def test_scoped_find_include
65
+ # with the include, will retrieve only developers for the given project
66
+ scoped_developers = Developer.with_scope(:find => { :include => :projects }) do
67
+ Developer.find(:all, :conditions => 'projects.id = 2')
68
+ end
69
+ assert scoped_developers.include?(developers(:david))
70
+ assert !scoped_developers.include?(developers(:jamis))
71
+ assert_equal 1, scoped_developers.size
72
+ end
73
+
74
+ def test_scoped_count_include
75
+ # with the include, will retrieve only developers for the given project
76
+ Developer.with_scope(:find => { :include => :projects }) do
77
+ assert_equal 1, Developer.count('projects.id = 2')
78
+ end
79
+ end
80
+
45
81
  def test_scoped_create
46
82
  new_comment = nil
47
83
 
48
84
  VerySpecialComment.with_scope(:create => { :post_id => 1 }) do
49
- assert_equal({ :post_id => 1 }, Thread.current[:scoped_methods][VerySpecialComment][:create])
85
+ assert_equal({ :post_id => 1 }, VerySpecialComment.send(:current_scoped_methods)[:create])
50
86
  new_comment = VerySpecialComment.create :body => "Wonderful world"
51
87
  end
52
88
 
@@ -69,11 +105,210 @@ class MethodScopingTest < Test::Unit::TestCase
69
105
  end
70
106
  end
71
107
 
72
- def test_raise_on_nested_scope
73
- Developer.with_scope(:find => { :conditions => '1=1' }) do
74
- assert_raise(ArgumentError) do
75
- Developer.with_scope(:find => { :conditions => '2=2' }) { }
108
+ def test_scoped_with_duck_typing
109
+ scoping = Struct.new(:method_scoping).new(:find => { :conditions => ["name = ?", 'David'] })
110
+ Developer.with_scope(scoping) do
111
+ assert_equal %w(David), Developer.find(:all).map { |d| d.name }
112
+ end
113
+ end
114
+
115
+ def test_ensure_that_method_scoping_is_correctly_restored
116
+ scoped_methods = Developer.instance_eval('current_scoped_methods')
117
+
118
+ begin
119
+ Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
120
+ raise "an exception"
121
+ end
122
+ rescue
123
+ end
124
+ assert_equal scoped_methods, Developer.instance_eval('current_scoped_methods')
125
+ end
126
+ end
127
+
128
+ class NestedScopingTest < Test::Unit::TestCase
129
+ fixtures :developers, :projects, :comments, :posts
130
+
131
+ def test_merge_options
132
+ Developer.with_scope(:find => { :conditions => 'salary = 80000' }) do
133
+ Developer.with_scope(:find => { :limit => 10 }) do
134
+ merged_option = Developer.instance_eval('current_scoped_methods')[:find]
135
+ assert_equal({ :conditions => 'salary = 80000', :limit => 10 }, merged_option)
136
+ end
137
+ end
138
+ end
139
+
140
+ def test_replace_options
141
+ Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
142
+ Developer.with_exclusive_scope(:find => { :conditions => "name = 'Jamis'" }) do
143
+ assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Developer.instance_eval('current_scoped_methods'))
144
+ assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Developer.send(:scoped_methods)[-1])
145
+ end
146
+ end
147
+ end
148
+
149
+ def test_append_conditions
150
+ Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
151
+ Developer.with_scope(:find => { :conditions => 'salary = 80000' }) do
152
+ appended_condition = Developer.instance_eval('current_scoped_methods')[:find][:conditions]
153
+ assert_equal("( name = 'David' ) AND ( salary = 80000 )", appended_condition)
154
+ assert_equal(1, Developer.count)
155
+ end
156
+ Developer.with_scope(:find => { :conditions => "name = 'Maiha'" }) do
157
+ assert_equal(0, Developer.count)
158
+ end
159
+ end
160
+ end
161
+
162
+ def test_merge_and_append_options
163
+ Developer.with_scope(:find => { :conditions => 'salary = 80000', :limit => 10 }) do
164
+ Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
165
+ merged_option = Developer.instance_eval('current_scoped_methods')[:find]
166
+ assert_equal({ :conditions => "( salary = 80000 ) AND ( name = 'David' )", :limit => 10 }, merged_option)
167
+ end
168
+ end
169
+ end
170
+
171
+ def test_nested_scoped_find
172
+ Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
173
+ Developer.with_exclusive_scope(:find => { :conditions => "name = 'David'" }) do
174
+ assert_nothing_raised { Developer.find(1) }
175
+ assert_equal('David', Developer.find(:first).name)
176
+ end
177
+ assert_equal('Jamis', Developer.find(:first).name)
178
+ end
179
+ end
180
+
181
+ def test_nested_scoped_find_include
182
+ Developer.with_scope(:find => { :include => :projects }) do
183
+ Developer.with_scope(:find => { :conditions => "projects.id = 2" }) do
184
+ assert_nothing_raised { Developer.find(1) }
185
+ assert_equal('David', Developer.find(:first).name)
186
+ end
187
+ end
188
+ end
189
+
190
+ def test_nested_scoped_find_merged_include
191
+ # :include's remain unique and don't "double up" when merging
192
+ Developer.with_scope(:find => { :include => :projects, :conditions => "projects.id = 2" }) do
193
+ Developer.with_scope(:find => { :include => :projects }) do
194
+ assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
195
+ assert_equal('David', Developer.find(:first).name)
196
+ end
197
+ end
198
+
199
+ # the nested scope doesn't remove the first :include
200
+ Developer.with_scope(:find => { :include => :projects, :conditions => "projects.id = 2" }) do
201
+ Developer.with_scope(:find => { :include => [] }) do
202
+ assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
203
+ assert_equal('David', Developer.find(:first).name)
204
+ end
205
+ end
206
+
207
+ # mixing array and symbol include's will merge correctly
208
+ Developer.with_scope(:find => { :include => [:projects], :conditions => "projects.id = 2" }) do
209
+ Developer.with_scope(:find => { :include => :projects }) do
210
+ assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
211
+ assert_equal('David', Developer.find(:first).name)
212
+ end
213
+ end
214
+ end
215
+
216
+ def test_nested_scoped_find_replace_include
217
+ Developer.with_scope(:find => { :include => :projects }) do
218
+ Developer.with_exclusive_scope(:find => { :include => [] }) do
219
+ assert_equal 0, Developer.instance_eval('current_scoped_methods')[:find][:include].length
220
+ end
221
+ end
222
+ end
223
+
224
+ def test_three_level_nested_exclusive_scoped_find
225
+ Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
226
+ assert_equal('Jamis', Developer.find(:first).name)
227
+
228
+ Developer.with_exclusive_scope(:find => { :conditions => "name = 'David'" }) do
229
+ assert_equal('David', Developer.find(:first).name)
230
+
231
+ Developer.with_exclusive_scope(:find => { :conditions => "name = 'Maiha'" }) do
232
+ assert_equal(nil, Developer.find(:first))
233
+ end
234
+
235
+ # ensure that scoping is restored
236
+ assert_equal('David', Developer.find(:first).name)
237
+ end
238
+
239
+ # ensure that scoping is restored
240
+ assert_equal('Jamis', Developer.find(:first).name)
241
+ end
242
+ end
243
+
244
+ def test_merged_scoped_find
245
+ poor_jamis = developers(:poor_jamis)
246
+ Developer.with_scope(:find => { :conditions => "salary < 100000" }) do
247
+ Developer.with_scope(:find => { :offset => 1 }) do
248
+ assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc'))
249
+ end
250
+ end
251
+ end
252
+
253
+ def test_merged_scoped_find_sanitizes_conditions
254
+ Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
255
+ Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
256
+ assert_raise(ActiveRecord::RecordNotFound) { developers(:poor_jamis) }
257
+ end
258
+ end
259
+ end
260
+
261
+ def test_nested_scoped_find_combines_and_sanitizes_conditions
262
+ Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
263
+ Developer.with_exclusive_scope(:find => { :conditions => ['salary = ?', 9000] }) do
264
+ assert_equal developers(:poor_jamis), Developer.find(:first)
265
+ assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => ['name = ?', 'Jamis'])
266
+ end
267
+ end
268
+ end
269
+
270
+ def test_merged_scoped_find_combines_and_sanitizes_conditions
271
+ Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
272
+ Developer.with_scope(:find => { :conditions => ['salary > ?', 9000] }) do
273
+ assert_equal %w(David), Developer.find(:all).map { |d| d.name }
274
+ end
275
+ end
276
+ end
277
+
278
+ def test_immutable_nested_scope
279
+ options1 = { :conditions => "name = 'Jamis'" }
280
+ options2 = { :conditions => "name = 'David'" }
281
+ Developer.with_scope(:find => options1) do
282
+ Developer.with_exclusive_scope(:find => options2) do
283
+ assert_equal %w(David), Developer.find(:all).map { |d| d.name }
284
+ options1[:conditions] = options2[:conditions] = nil
285
+ assert_equal %w(David), Developer.find(:all).map { |d| d.name }
286
+ end
287
+ end
288
+ end
289
+
290
+ def test_immutable_merged_scope
291
+ options1 = { :conditions => "name = 'Jamis'" }
292
+ options2 = { :conditions => "salary > 10000" }
293
+ Developer.with_scope(:find => options1) do
294
+ Developer.with_scope(:find => options2) do
295
+ assert_equal %w(Jamis), Developer.find(:all).map { |d| d.name }
296
+ options1[:conditions] = options2[:conditions] = nil
297
+ assert_equal %w(Jamis), Developer.find(:all).map { |d| d.name }
298
+ end
299
+ end
300
+ end
301
+
302
+ def test_ensure_that_method_scoping_is_correctly_restored
303
+ Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
304
+ scoped_methods = Developer.instance_eval('current_scoped_methods')
305
+ begin
306
+ Developer.with_scope(:find => { :conditions => "name = 'Maiha'" }) do
307
+ raise "an exception"
308
+ end
309
+ rescue
76
310
  end
311
+ assert_equal scoped_methods, Developer.instance_eval('current_scoped_methods')
77
312
  end
78
313
  end
79
314
  end
@@ -100,9 +335,9 @@ class HasManyScopingTest< Test::Unit::TestCase
100
335
  assert_equal 2, @welcome.comments.find_all_by_type('Comment').size
101
336
  end
102
337
 
103
- def test_raise_on_nested_scope
338
+ def test_nested_scope
104
339
  Comment.with_scope(:find => { :conditions => '1=1' }) do
105
- assert_raise(ArgumentError) { @welcome.comments.what_are_you }
340
+ assert_equal 'a comment...', @welcome.comments.what_are_you
106
341
  end
107
342
  end
108
343
  end
@@ -121,14 +356,14 @@ class HasAndBelongsToManyScopingTest< Test::Unit::TestCase
121
356
  end
122
357
 
123
358
  def test_forwarding_to_dynamic_finders
124
- assert_equal 1, Category.find_all_by_type('SpecialCategory').size
359
+ assert_equal 4, Category.find_all_by_type('SpecialCategory').size
125
360
  assert_equal 0, @welcome.categories.find_all_by_type('SpecialCategory').size
126
361
  assert_equal 2, @welcome.categories.find_all_by_type('Category').size
127
362
  end
128
363
 
129
- def test_raise_on_nested_scope
364
+ def test_nested_scope
130
365
  Category.with_scope(:find => { :conditions => '1=1' }) do
131
- assert_raise(ArgumentError) { @welcome.categories.what_are_you }
366
+ assert_equal 'a comment...', @welcome.comments.what_are_you
132
367
  end
133
368
  end
134
369
  end