activerecord 1.1.0 → 1.2.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 +250 -0
- data/README +17 -9
- data/dev-utils/eval_debugger.rb +1 -1
- data/install.rb +3 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/acts/list.rb +178 -0
- data/lib/active_record/acts/tree.rb +44 -0
- data/lib/active_record/associations.rb +45 -8
- data/lib/active_record/associations/association_collection.rb +18 -9
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +14 -13
- data/lib/active_record/associations/has_many_association.rb +21 -12
- data/lib/active_record/base.rb +137 -37
- data/lib/active_record/callbacks.rb +30 -25
- data/lib/active_record/connection_adapters/abstract_adapter.rb +57 -33
- data/lib/active_record/connection_adapters/mysql_adapter.rb +4 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +3 -2
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +298 -0
- data/lib/active_record/fixtures.rb +241 -147
- data/lib/active_record/support/class_inheritable_attributes.rb +5 -2
- data/lib/active_record/support/inflector.rb +13 -12
- data/lib/active_record/support/misc.rb +6 -0
- data/lib/active_record/timestamp.rb +33 -0
- data/lib/active_record/transactions.rb +1 -1
- data/lib/active_record/validations.rb +294 -16
- data/rakefile +3 -7
- data/test/abstract_unit.rb +1 -4
- data/test/associations_test.rb +17 -4
- data/test/base_test.rb +37 -5
- data/test/connections/native_sqlserver/connection.rb +15 -0
- data/test/deprecated_associations_test.rb +40 -38
- data/test/finder_test.rb +82 -4
- data/test/fixtures/accounts.yml +8 -0
- data/test/fixtures/company.rb +6 -0
- data/test/fixtures/company_in_module.rb +1 -1
- data/test/fixtures/db_definitions/mysql.sql +13 -0
- data/test/fixtures/db_definitions/postgresql.sql +13 -0
- data/test/fixtures/db_definitions/sqlite.sql +14 -0
- data/test/fixtures/db_definitions/sqlserver.sql +110 -0
- data/test/fixtures/db_definitions/sqlserver2.sql +4 -0
- data/test/fixtures/developer.rb +2 -2
- data/test/fixtures/developers.yml +13 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/mixin.rb +17 -0
- data/test/fixtures/mixins.yml +14 -0
- data/test/fixtures/naked/csv/accounts.csv +1 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/project.rb +6 -0
- data/test/fixtures/reply.rb +14 -1
- data/test/fixtures/topic.rb +2 -2
- data/test/fixtures/topics/first +1 -0
- data/test/fixtures_test.rb +42 -12
- data/test/inflector_test.rb +2 -1
- data/test/inheritance_test.rb +22 -12
- data/test/mixin_test.rb +138 -0
- data/test/pk_test.rb +4 -2
- data/test/reflection_test.rb +3 -3
- data/test/transactions_test.rb +15 -0
- data/test/validations_test.rb +229 -4
- metadata +24 -10
- data/lib/active_record/associations.rb.orig +0 -555
- data/test/deprecated_associations_test.rb.orig +0 -334
- data/test/fixtures/accounts/signals37 +0 -3
- data/test/fixtures/accounts/unknown +0 -2
- data/test/fixtures/developers/david +0 -2
- data/test/fixtures/developers/jamis +0 -2
data/test/finder_test.rb
CHANGED
@@ -1,20 +1,27 @@
|
|
1
1
|
require 'abstract_unit'
|
2
2
|
require 'fixtures/company'
|
3
3
|
require 'fixtures/topic'
|
4
|
+
require 'fixtures/entrant'
|
4
5
|
|
5
6
|
class FinderTest < Test::Unit::TestCase
|
6
7
|
def setup
|
7
8
|
@company_fixtures = create_fixtures("companies")
|
8
9
|
@topic_fixtures = create_fixtures("topics")
|
10
|
+
@entrant_fixtures = create_fixtures("entrants")
|
9
11
|
end
|
10
12
|
|
11
13
|
def test_find
|
12
14
|
assert_equal(@topic_fixtures["first"]["title"], Topic.find(1).title)
|
13
15
|
end
|
14
16
|
|
17
|
+
def test_find_by_array_of_one_id
|
18
|
+
assert_kind_of(Array, Topic.find([ 1 ]))
|
19
|
+
assert_equal(1, Topic.find([ 1 ]).length)
|
20
|
+
end
|
21
|
+
|
15
22
|
def test_find_by_ids
|
16
23
|
assert_equal(2, Topic.find(1, 2).length)
|
17
|
-
assert_equal(@topic_fixtures["second"]["title"], Topic.find([ 2 ]).title)
|
24
|
+
assert_equal(@topic_fixtures["second"]["title"], Topic.find([ 2 ]).first.title)
|
18
25
|
end
|
19
26
|
|
20
27
|
def test_find_by_ids_missing_one
|
@@ -23,6 +30,20 @@ class FinderTest < Test::Unit::TestCase
|
|
23
30
|
}
|
24
31
|
end
|
25
32
|
|
33
|
+
def test_find_all_with_limit
|
34
|
+
entrants = Entrant.find_all nil, "id ASC", 2
|
35
|
+
|
36
|
+
assert_equal(2, entrants.size)
|
37
|
+
assert_equal(@entrant_fixtures["first"]["name"], entrants.first.name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_find_all_with_prepared_limit_and_offset
|
41
|
+
entrants = Entrant.find_all nil, "id ASC", ["? OFFSET ?", 2, 1]
|
42
|
+
|
43
|
+
assert_equal(2, entrants.size)
|
44
|
+
assert_equal(@entrant_fixtures["second"]["name"], entrants.first.name)
|
45
|
+
end
|
46
|
+
|
26
47
|
def test_find_with_entire_select_statement
|
27
48
|
topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
|
28
49
|
|
@@ -30,6 +51,13 @@ class FinderTest < Test::Unit::TestCase
|
|
30
51
|
assert_equal(@topic_fixtures["second"]["title"], topics.first.title)
|
31
52
|
end
|
32
53
|
|
54
|
+
def test_find_with_prepared_select_statement
|
55
|
+
topics = Topic.find_by_sql ["SELECT * FROM topics WHERE author_name = ?", "Mary"]
|
56
|
+
|
57
|
+
assert_equal(1, topics.size)
|
58
|
+
assert_equal(@topic_fixtures["second"]["title"], topics.first.title)
|
59
|
+
end
|
60
|
+
|
33
61
|
def test_find_first
|
34
62
|
first = Topic.find_first "title = 'The First Topic'"
|
35
63
|
assert_equal(@topic_fixtures["first"]["title"], first.title)
|
@@ -60,8 +88,58 @@ class FinderTest < Test::Unit::TestCase
|
|
60
88
|
assert_kind_of Time, Topic.find_first(["id = %d", 1]).written_on
|
61
89
|
end
|
62
90
|
|
91
|
+
def test_bind_variables
|
92
|
+
assert_kind_of Firm, Company.find_first(["name = ?", "37signals"])
|
93
|
+
assert_nil Company.find_first(["name = ?", "37signals!"])
|
94
|
+
assert_nil Company.find_first(["name = ?", "37signals!' OR 1=1"])
|
95
|
+
assert_kind_of Time, Topic.find_first(["id = ?", 1]).written_on
|
96
|
+
assert_raises(ActiveRecord::PreparedStatementInvalid) {
|
97
|
+
Company.find_first(["id=? AND name = ?", 2])
|
98
|
+
}
|
99
|
+
assert_raises(ActiveRecord::PreparedStatementInvalid) {
|
100
|
+
Company.find_first(["id=?", 2, 3, 4])
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_bind_variables_with_quotes
|
105
|
+
Company.create("name" => "37signals' go'es agains")
|
106
|
+
assert Company.find_first(["name = ?", "37signals' go'es agains"])
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_named_bind_variables_with_quotes
|
110
|
+
Company.create("name" => "37signals' go'es agains")
|
111
|
+
assert Company.find_first(["name = :name", {:name => "37signals' go'es agains"}])
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_named_bind_variables
|
115
|
+
assert_kind_of Firm, Company.find_first(["name = :name", { :name => "37signals" }])
|
116
|
+
assert_nil Company.find_first(["name = :name", { :name => "37signals!" }])
|
117
|
+
assert_nil Company.find_first(["name = :name", { :name => "37signals!' OR 1=1" }])
|
118
|
+
assert_kind_of Time, Topic.find_first(["id = :id", { :id => 1 }]).written_on
|
119
|
+
assert_raises(ActiveRecord::PreparedStatementInvalid) {
|
120
|
+
Company.find_first(["id=:id and name=:name", { :id=>3 }])
|
121
|
+
}
|
122
|
+
assert_raises(ActiveRecord::PreparedStatementInvalid) {
|
123
|
+
Company.find_first(["id=:id", { :id=>3, :name=>"37signals!" }])
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
|
63
129
|
def test_string_sanitation
|
64
|
-
|
65
|
-
assert_equal "something select table", ActiveRecord::Base.sanitize("something; select table")
|
130
|
+
assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
|
131
|
+
assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_count
|
135
|
+
assert_equal(0, Entrant.count("id > 3"))
|
136
|
+
assert_equal(1, Entrant.count(["id > ?", 2]))
|
137
|
+
assert_equal(2, Entrant.count(["id > ?", 1]))
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_count_by_sql
|
141
|
+
assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
|
142
|
+
assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
|
143
|
+
assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
|
66
144
|
end
|
67
|
-
end
|
145
|
+
end
|
data/test/fixtures/company.rb
CHANGED
@@ -9,6 +9,12 @@ class Firm < Company
|
|
9
9
|
has_many :clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id"
|
10
10
|
has_many :clients_like_ms, :conditions => "name = 'Microsoft'", :class_name => "Client", :order => "id"
|
11
11
|
has_many :clients_using_sql, :class_name => "Client", :finder_sql => 'SELECT * FROM companies WHERE client_of = #{id}'
|
12
|
+
has_many :clients_using_counter_sql, :class_name => "Client",
|
13
|
+
:finder_sql => 'SELECT * FROM companies WHERE client_of = #{id}',
|
14
|
+
:counter_sql => 'SELECT COUNT(*) FROM companies WHERE client_of = #{id}'
|
15
|
+
has_many :clients_using_zero_counter_sql, :class_name => "Client",
|
16
|
+
:finder_sql => 'SELECT * FROM companies WHERE client_of = #{id}',
|
17
|
+
:counter_sql => 'SELECT 0 FROM companies WHERE client_of = #{id}'
|
12
18
|
|
13
19
|
has_one :account, :dependent => true
|
14
20
|
end
|
@@ -23,6 +23,7 @@ CREATE TABLE `topics` (
|
|
23
23
|
`author_name` varchar(255) default NULL,
|
24
24
|
`author_email_address` varchar(255) default NULL,
|
25
25
|
`written_on` datetime default NULL,
|
26
|
+
`bonus_time` time default NULL,
|
26
27
|
`last_read` date default NULL,
|
27
28
|
`content` text,
|
28
29
|
`approved` tinyint(1) default 1,
|
@@ -95,3 +96,15 @@ CREATE TABLE `colnametests` (
|
|
95
96
|
`references` int(11) NOT NULL,
|
96
97
|
PRIMARY KEY (`id`)
|
97
98
|
);
|
99
|
+
|
100
|
+
CREATE TABLE `mixins` (
|
101
|
+
`id` int(11) NOT NULL auto_increment,
|
102
|
+
`parent_id` int(11) default NULL,
|
103
|
+
`pos` int(11) default NULL,
|
104
|
+
`lft` int(11) default NULL,
|
105
|
+
`rgt` int(11) default NULL,
|
106
|
+
`root_id` int(11) default NULL,
|
107
|
+
`created_at` datetime default NULL,
|
108
|
+
`updated_at` datetime default NULL,
|
109
|
+
PRIMARY KEY (`id`)
|
110
|
+
);
|
@@ -46,6 +46,7 @@ CREATE TABLE topics (
|
|
46
46
|
author_name character varying(255),
|
47
47
|
author_email_address character varying(255),
|
48
48
|
written_on timestamp without time zone,
|
49
|
+
bonus_time time,
|
49
50
|
last_read date,
|
50
51
|
content text,
|
51
52
|
replies_count integer default 0,
|
@@ -112,3 +113,15 @@ CREATE TABLE colnametests (
|
|
112
113
|
id serial,
|
113
114
|
"references" integer NOT NULL
|
114
115
|
);
|
116
|
+
|
117
|
+
CREATE TABLE mixins (
|
118
|
+
id serial,
|
119
|
+
parent_id integer,
|
120
|
+
pos integer,
|
121
|
+
lft integer,
|
122
|
+
rgt integer,
|
123
|
+
root_id integer,
|
124
|
+
created_at timestamp,
|
125
|
+
updated_at timestamp,
|
126
|
+
PRIMARY KEY (id)
|
127
|
+
);
|
@@ -21,6 +21,7 @@ CREATE TABLE 'topics' (
|
|
21
21
|
'author_name' VARCHAR(255) DEFAULT NULL,
|
22
22
|
'author_email_address' VARCHAR(255) DEFAULT NULL,
|
23
23
|
'written_on' DATETIME DEFAULT NULL,
|
24
|
+
'bonus_time' TIME DEFAULT NULL,
|
24
25
|
'last_read' DATE DEFAULT NULL,
|
25
26
|
'content' TEXT,
|
26
27
|
'approved' INTEGER DEFAULT 1,
|
@@ -84,3 +85,16 @@ CREATE TABLE 'colnametests' (
|
|
84
85
|
'id' INTEGER NOT NULL PRIMARY KEY,
|
85
86
|
'references' INTEGER NOT NULL
|
86
87
|
);
|
88
|
+
|
89
|
+
CREATE TABLE 'mixins' (
|
90
|
+
'id' INTEGER NOT NULL PRIMARY KEY,
|
91
|
+
'parent_id' INTEGER DEFAULT NULL,
|
92
|
+
'pos' INTEGER DEFAULT NULL,
|
93
|
+
'lft' INTEGER DEFAULT NULL,
|
94
|
+
'rgt' INTEGER DEFAULT NULL,
|
95
|
+
'root_id' INTEGER DEFAULT NULL,
|
96
|
+
'created_at' DATETIME DEFAULT NULL,
|
97
|
+
'updated_at' DATETIME DEFAULT NULL
|
98
|
+
);
|
99
|
+
|
100
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
CREATE TABLE accounts (
|
2
|
+
id int NOT NULL IDENTITY(1, 1),
|
3
|
+
firm_id int default NULL,
|
4
|
+
credit_limit int default NULL,
|
5
|
+
PRIMARY KEY (id)
|
6
|
+
)
|
7
|
+
|
8
|
+
CREATE TABLE companies (
|
9
|
+
id int NOT NULL IDENTITY(1, 1),
|
10
|
+
type varchar(50) default NULL,
|
11
|
+
ruby_type varchar(50) default NULL,
|
12
|
+
firm_id int default NULL,
|
13
|
+
name varchar(50) default NULL,
|
14
|
+
client_of int default NULL,
|
15
|
+
companies_count int default 0,
|
16
|
+
rating int default 1,
|
17
|
+
PRIMARY KEY (id)
|
18
|
+
)
|
19
|
+
|
20
|
+
CREATE TABLE topics (
|
21
|
+
id int NOT NULL IDENTITY(1, 1),
|
22
|
+
title varchar(255) default NULL,
|
23
|
+
author_name varchar(255) default NULL,
|
24
|
+
author_email_address varchar(255) default NULL,
|
25
|
+
written_on datetime default NULL,
|
26
|
+
last_read datetime default NULL,
|
27
|
+
content text,
|
28
|
+
approved tinyint default 1,
|
29
|
+
replies_count int default 0,
|
30
|
+
parent_id int default NULL,
|
31
|
+
type varchar(50) default NULL,
|
32
|
+
PRIMARY KEY (id)
|
33
|
+
)
|
34
|
+
|
35
|
+
CREATE TABLE developers (
|
36
|
+
id int NOT NULL IDENTITY(1, 1),
|
37
|
+
name varchar(100) default NULL,
|
38
|
+
PRIMARY KEY (id)
|
39
|
+
);
|
40
|
+
|
41
|
+
CREATE TABLE projects (
|
42
|
+
id int NOT NULL IDENTITY(1, 1),
|
43
|
+
name varchar(100) default NULL,
|
44
|
+
PRIMARY KEY (id)
|
45
|
+
);
|
46
|
+
|
47
|
+
CREATE TABLE developers_projects (
|
48
|
+
developer_id int NOT NULL,
|
49
|
+
project_id int NOT NULL
|
50
|
+
);
|
51
|
+
|
52
|
+
CREATE TABLE customers (
|
53
|
+
id int NOT NULL IDENTITY(1, 1),
|
54
|
+
name varchar(100) default NULL,
|
55
|
+
balance int default 0,
|
56
|
+
address_street varchar(100) default NULL,
|
57
|
+
address_city varchar(100) default NULL,
|
58
|
+
address_country varchar(100) default NULL,
|
59
|
+
PRIMARY KEY (id)
|
60
|
+
);
|
61
|
+
|
62
|
+
CREATE TABLE movies (
|
63
|
+
movieid int NOT NULL IDENTITY(1, 1),
|
64
|
+
name varchar(100) default NULL,
|
65
|
+
PRIMARY KEY (movieid)
|
66
|
+
);
|
67
|
+
|
68
|
+
CREATE TABLE subscribers (
|
69
|
+
nick varchar(100) NOT NULL,
|
70
|
+
name varchar(100) default NULL,
|
71
|
+
PRIMARY KEY (nick)
|
72
|
+
);
|
73
|
+
|
74
|
+
CREATE TABLE booleantests (
|
75
|
+
id int NOT NULL IDENTITY(1, 1),
|
76
|
+
value integer default NULL,
|
77
|
+
PRIMARY KEY (id)
|
78
|
+
);
|
79
|
+
|
80
|
+
CREATE TABLE auto_id_tests (
|
81
|
+
auto_id int NOT NULL IDENTITY(1, 1),
|
82
|
+
value int default NULL,
|
83
|
+
PRIMARY KEY (auto_id)
|
84
|
+
);
|
85
|
+
|
86
|
+
CREATE TABLE entrants (
|
87
|
+
id int NOT NULL PRIMARY KEY,
|
88
|
+
name varchar(255) NOT NULL,
|
89
|
+
course_id int NOT NULL
|
90
|
+
);
|
91
|
+
|
92
|
+
CREATE TABLE colnametests (
|
93
|
+
id int NOT NULL IDENTITY(1, 1),
|
94
|
+
[references] int NOT NULL,
|
95
|
+
PRIMARY KEY (id)
|
96
|
+
);
|
97
|
+
|
98
|
+
CREATE TABLE mixins (
|
99
|
+
id int NOT NULL IDENTITY(1, 1),
|
100
|
+
parent_id int default NULL,
|
101
|
+
pos int default NULL,
|
102
|
+
lft int default NULL,
|
103
|
+
rgt int default NULL,
|
104
|
+
root_id int default NULL,
|
105
|
+
created_at datetime default NULL,
|
106
|
+
updated_at datetime default NULL,
|
107
|
+
PRIMARY KEY (id)
|
108
|
+
);
|
109
|
+
|
110
|
+
|
data/test/fixtures/developer.rb
CHANGED
Binary file
|
Binary file
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Mixin < ActiveRecord::Base
|
2
|
+
acts_as_tree :foreign_key => "parent_id", :order => "id"
|
3
|
+
|
4
|
+
end
|
5
|
+
|
6
|
+
class ListMixin < ActiveRecord::Base
|
7
|
+
acts_as_list :column => "pos", :scope => :parent
|
8
|
+
|
9
|
+
def self.table_name() "mixins" end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
class ListWithStringScopeMixin < ActiveRecord::Base
|
14
|
+
acts_as_list :column => "pos", :scope => 'parent_id = #{parent_id}'
|
15
|
+
|
16
|
+
def self.table_name() "mixins" end
|
17
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
# i wonder what will happen here
|
@@ -0,0 +1 @@
|
|
1
|
+
qwerty
|
data/test/fixtures/project.rb
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
class Project < ActiveRecord::Base
|
2
2
|
has_and_belongs_to_many :developers, :uniq => true
|
3
3
|
has_and_belongs_to_many :developers_named_david, :class_name => "Developer", :conditions => "name = 'David'", :uniq => true
|
4
|
+
end
|
5
|
+
|
6
|
+
class SpecialProject < Project
|
7
|
+
def hello_world
|
8
|
+
"hello there!"
|
9
|
+
end
|
4
10
|
end
|
data/test/fixtures/reply.rb
CHANGED
@@ -1,21 +1,34 @@
|
|
1
1
|
class Reply < Topic
|
2
2
|
belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true
|
3
|
+
has_many :silly_replies, :dependent => true, :foreign_key => "parent_id"
|
4
|
+
|
5
|
+
validate :errors_on_empty_content
|
6
|
+
validate_on_create :title_is_wrong_create
|
3
7
|
|
4
8
|
attr_accessible :title, :author_name, :author_email_address, :written_on, :content, :last_read
|
5
9
|
|
6
10
|
def validate
|
7
11
|
errors.add("title", "Empty") unless attribute_present? "title"
|
12
|
+
end
|
13
|
+
|
14
|
+
def errors_on_empty_content
|
8
15
|
errors.add("content", "Empty") unless attribute_present? "content"
|
9
16
|
end
|
10
17
|
|
11
18
|
def validate_on_create
|
12
|
-
errors.add("title", "is Wrong Create") if attribute_present?("title") && title == "Wrong Create"
|
13
19
|
if attribute_present?("title") && attribute_present?("content") && content == "Mismatch"
|
14
20
|
errors.add("title", "is Content Mismatch")
|
15
21
|
end
|
16
22
|
end
|
17
23
|
|
24
|
+
def title_is_wrong_create
|
25
|
+
errors.add("title", "is Wrong Create") if attribute_present?("title") && title == "Wrong Create"
|
26
|
+
end
|
27
|
+
|
18
28
|
def validate_on_update
|
19
29
|
errors.add("title", "is Wrong Update") if attribute_present?("title") && title == "Wrong Update"
|
20
30
|
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class SillyReply < Reply
|
21
34
|
end
|