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.
- data/CHANGELOG +452 -10
- data/RUNNING_UNIT_TESTS +1 -1
- data/lib/active_record.rb +5 -2
- data/lib/active_record/acts/list.rb +1 -1
- data/lib/active_record/acts/tree.rb +29 -25
- data/lib/active_record/aggregations.rb +3 -2
- data/lib/active_record/associations.rb +783 -337
- data/lib/active_record/associations/association_collection.rb +7 -12
- data/lib/active_record/associations/association_proxy.rb +62 -24
- data/lib/active_record/associations/belongs_to_association.rb +27 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +38 -38
- data/lib/active_record/associations/has_many_association.rb +61 -56
- data/lib/active_record/associations/has_many_through_association.rb +144 -0
- data/lib/active_record/associations/has_one_association.rb +22 -16
- data/lib/active_record/base.rb +482 -182
- data/lib/active_record/calculations.rb +225 -0
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +162 -47
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +21 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +34 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +107 -61
- data/lib/active_record/connection_adapters/mysql_adapter.rb +29 -6
- data/lib/active_record/connection_adapters/openbase_adapter.rb +349 -0
- data/lib/active_record/connection_adapters/{oci_adapter.rb → oracle_adapter.rb} +125 -59
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +24 -21
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +47 -8
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +36 -16
- data/lib/active_record/connection_adapters/sybase_adapter.rb +684 -0
- data/lib/active_record/fixtures.rb +42 -17
- data/lib/active_record/locking.rb +36 -15
- data/lib/active_record/migration.rb +111 -8
- data/lib/active_record/observer.rb +25 -1
- data/lib/active_record/reflection.rb +103 -41
- data/lib/active_record/schema.rb +2 -2
- data/lib/active_record/schema_dumper.rb +55 -18
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/validations.rb +65 -40
- data/lib/active_record/vendor/db2.rb +10 -5
- data/lib/active_record/vendor/simple.rb +693 -702
- data/lib/active_record/version.rb +2 -2
- data/rakefile +4 -4
- data/test/aaa_create_tables_test.rb +25 -6
- data/test/abstract_unit.rb +39 -1
- data/test/adapter_test.rb +31 -4
- data/test/associations_cascaded_eager_loading_test.rb +106 -0
- data/test/associations_go_eager_test.rb +85 -16
- data/test/associations_join_model_test.rb +338 -0
- data/test/associations_test.rb +129 -50
- data/test/base_test.rb +204 -49
- data/test/binary_test.rb +1 -1
- data/test/calculations_test.rb +169 -0
- data/test/callbacks_test.rb +5 -23
- data/test/class_inheritable_attributes_test.rb +1 -1
- data/test/column_alias_test.rb +1 -1
- data/test/connections/native_mysql/connection.rb +1 -0
- data/test/connections/native_openbase/connection.rb +22 -0
- data/test/connections/{native_oci → native_oracle}/connection.rb +7 -9
- data/test/connections/native_sqlite/connection.rb +1 -1
- data/test/connections/native_sqlite3/connection.rb +1 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -0
- data/test/connections/native_sybase/connection.rb +24 -0
- data/test/defaults_test.rb +18 -0
- data/test/deprecated_associations_test.rb +2 -2
- data/test/deprecated_finder_test.rb +0 -6
- data/test/finder_test.rb +26 -23
- data/test/fixtures/accounts.yml +10 -0
- data/test/fixtures/author.rb +31 -6
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories_posts.yml +4 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +11 -0
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +17 -5
- data/test/fixtures/company_in_module.rb +19 -5
- data/test/fixtures/db_definitions/db2.drop.sql +3 -0
- data/test/fixtures/db_definitions/db2.sql +121 -100
- data/test/fixtures/db_definitions/db22.sql +2 -2
- data/test/fixtures/db_definitions/firebird.drop.sql +4 -0
- data/test/fixtures/db_definitions/firebird.sql +26 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +3 -0
- data/test/fixtures/db_definitions/mysql.sql +21 -1
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +282 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/{oci.drop.sql → oracle.drop.sql} +6 -0
- data/test/fixtures/db_definitions/{oci.sql → oracle.sql} +25 -4
- data/test/fixtures/db_definitions/{oci2.drop.sql → oracle2.drop.sql} +0 -0
- data/test/fixtures/db_definitions/{oci2.sql → oracle2.sql} +0 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +4 -0
- data/test/fixtures/db_definitions/postgresql.sql +22 -1
- data/test/fixtures/db_definitions/schema.rb +32 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlite.sql +18 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlserver.sql +23 -3
- data/test/fixtures/db_definitions/sybase.drop.sql +31 -0
- data/test/fixtures/db_definitions/sybase.sql +204 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/developers.yml +6 -1
- data/test/fixtures/developers_projects.yml +4 -0
- data/test/fixtures/funny_jokes.yml +14 -0
- data/test/fixtures/joke.rb +6 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/mixin.rb +1 -1
- data/test/fixtures/person.rb +4 -1
- data/test/fixtures/post.rb +26 -1
- data/test/fixtures/project.rb +1 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +2 -1
- data/test/fixtures/tag.rb +5 -0
- data/test/fixtures/tagging.rb +6 -0
- data/test/fixtures/taggings.yml +18 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/tasks.yml +2 -2
- data/test/fixtures/topic.rb +2 -2
- data/test/fixtures/topics.yml +1 -0
- data/test/fixtures_test.rb +47 -13
- data/test/inheritance_test.rb +2 -2
- data/test/locking_test.rb +15 -1
- data/test/method_scoping_test.rb +248 -13
- data/test/migration_test.rb +68 -11
- data/test/mixin_nested_set_test.rb +1 -1
- data/test/modules_test.rb +6 -1
- data/test/readonly_test.rb +1 -1
- data/test/reflection_test.rb +63 -9
- data/test/schema_dumper_test.rb +41 -0
- data/test/{synonym_test_oci.rb → synonym_test_oracle.rb} +1 -1
- data/test/threaded_connections_test.rb +10 -0
- data/test/unconnected_test.rb +12 -5
- data/test/validations_test.rb +197 -10
- metadata +295 -260
- data/test/fixtures/db_definitions/create_oracle_db.bat +0 -0
- data/test/fixtures/db_definitions/create_oracle_db.sh +0 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
data/test/fixtures/mixin.rb
CHANGED
data/test/fixtures/person.rb
CHANGED
data/test/fixtures/post.rb
CHANGED
@@ -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
|
data/test/fixtures/project.rb
CHANGED
@@ -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}'
|
data/test/fixtures/reply.rb
CHANGED
@@ -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 :
|
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,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
|
data/test/fixtures/tasks.yml
CHANGED
@@ -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:
|
5
|
-
ending:
|
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
|
data/test/fixtures/topic.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
class Topic < ActiveRecord::Base
|
2
|
-
has_many :replies, :dependent =>
|
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
|
-
|
9
|
+
Topic.find(parent_id)
|
10
10
|
end
|
11
11
|
|
12
12
|
protected
|
data/test/fixtures/topics.yml
CHANGED
data/test/fixtures_test.rb
CHANGED
@@ -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, :
|
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
|
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
|
data/test/inheritance_test.rb
CHANGED
@@ -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) }
|
data/test/locking_test.rb
CHANGED
@@ -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
|
data/test/method_scoping_test.rb
CHANGED
@@ -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...',
|
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 [
|
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 },
|
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
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
338
|
+
def test_nested_scope
|
104
339
|
Comment.with_scope(:find => { :conditions => '1=1' }) do
|
105
|
-
|
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
|
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
|
364
|
+
def test_nested_scope
|
130
365
|
Category.with_scope(:find => { :conditions => '1=1' }) do
|
131
|
-
|
366
|
+
assert_equal 'a comment...', @welcome.comments.what_are_you
|
132
367
|
end
|
133
368
|
end
|
134
369
|
end
|