activerecord 1.8.0 → 1.9.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 +34 -0
- data/lib/active_record/acts/list.rb +1 -1
- data/lib/active_record/base.rb +18 -5
- data/lib/active_record/callbacks.rb +21 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +20 -7
- data/lib/active_record/connection_adapters/db2_adapter.rb +5 -1
- data/lib/active_record/connection_adapters/mysql_adapter.rb +15 -11
- data/lib/active_record/connection_adapters/oci_adapter.rb +14 -15
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +6 -13
- data/lib/active_record/fixtures.rb +62 -16
- data/lib/active_record/migration.rb +3 -3
- data/lib/active_record/validations.rb +46 -56
- data/rakefile +2 -2
- data/test/active_schema_mysql.rb +31 -0
- data/test/callbacks_test.rb +61 -19
- data/test/connections/native_sqlite/connection.rb +1 -1
- data/test/connections/native_sqlite3/connection.rb +1 -1
- data/test/finder_test.rb +39 -1
- data/test/fixtures/db_definitions/sqlserver.sql +1 -1
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures_test.rb +36 -1
- data/test/validations_test.rb +16 -16
- metadata +5 -4
data/CHANGELOG
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
*1.9.0* (22th March, 2005)
|
2
|
+
|
3
|
+
* Added adapter independent limit clause as a two-element array with the first being the limit, the second being the offset #795 [Sam Stephenson]. Example:
|
4
|
+
|
5
|
+
Developer.find_all nil, 'id ASC', 5 # return the first five developers
|
6
|
+
Developer.find_all nil, 'id ASC', [3, 8] # return three developers, starting from #8 and forward
|
7
|
+
|
8
|
+
This doesn't yet work with the DB2 or MS SQL adapters. Patches to make that happen are encouraged.
|
9
|
+
|
10
|
+
* Added alias_method :to_param, :id to Base, such that Active Record objects to be used as URL parameters in Action Pack automatically #812 [Nicholas Seckar/Sam Stephenson]
|
11
|
+
|
12
|
+
* Improved the performance of the OCI8 adapter for Oracle #723 [pilx/gjenkins]
|
13
|
+
|
14
|
+
* Added type conversion before saving a record, so string-based values like "10.0" aren't left for the database to convert #820 [dave@cherryville.org]
|
15
|
+
|
16
|
+
* Added with additional settings for working with transactional fixtures and pre-loaded test databases #865 [mindel]
|
17
|
+
|
18
|
+
* Fixed acts_as_list to trigger remove_from_list on destroy after the fact, not before, so a unique position can be maintained #871 [Alisdair McDiarmid]
|
19
|
+
|
20
|
+
* Added the possibility of specifying fixtures in multiple calls #816 [kim@tinker.com]
|
21
|
+
|
22
|
+
* Added Base.exists?(id) that'll return true if an object of the class with the given id exists #854 [stian@grytoyr.net]
|
23
|
+
|
24
|
+
* Added optionally allow for nil or empty strings with validates_numericality_of #801 [Sebastian Kanthak]
|
25
|
+
|
26
|
+
* Fixed problem with using slashes in validates_format_of regular expressions #801 [Sebastian Kanthak]
|
27
|
+
|
28
|
+
* Fixed that SQLite3 exceptions are caught and reported properly #823 [yerejm]
|
29
|
+
|
30
|
+
* Added that all types of after_find/after_initialized callbacks are triggered if the explicit implementation is present, not only the explicit implementation itself
|
31
|
+
|
32
|
+
* Fixed that symbols can be used on attribute assignment, like page.emails.create(:subject => data.subject, :body => data.body)
|
33
|
+
|
34
|
+
|
1
35
|
*1.8.0* (7th March, 2005)
|
2
36
|
|
3
37
|
* Added ActiveRecord::Base.colorize_logging to control whether to use colors in logs or not (on by default)
|
data/lib/active_record/base.rb
CHANGED
@@ -326,6 +326,13 @@ module ActiveRecord #:nodoc:
|
|
326
326
|
end
|
327
327
|
end
|
328
328
|
|
329
|
+
# Returns true if the given +id+ represents the primary key of a record in the database, false otherwise.
|
330
|
+
# Example:
|
331
|
+
# Person.exists?(5)
|
332
|
+
def exists?(id)
|
333
|
+
!find_first("#{primary_key} = #{sanitize(id)}").nil?
|
334
|
+
end
|
335
|
+
|
329
336
|
# This method is deprecated in favor of find with the :conditions option.
|
330
337
|
# Works like find, but the record matching +id+ must also meet the +conditions+.
|
331
338
|
# +RecordNotFound+ is raised if no record can be found matching the +id+ or meeting the condition.
|
@@ -339,16 +346,18 @@ module ActiveRecord #:nodoc:
|
|
339
346
|
# table in the database. The +conditions+ can be used to narrow the selection of objects (WHERE-part),
|
340
347
|
# such as by "color = 'red'", and arrangement of the selection can be done through +orderings+ (ORDER BY-part),
|
341
348
|
# such as by "last_name, first_name DESC". A maximum of returned objects and their offset can be specified in
|
342
|
-
# +limit+
|
349
|
+
# +limit+ with either just a single integer as the limit or as an array with the first element as the limit,
|
350
|
+
# the second as the offset. Examples:
|
343
351
|
# Project.find_all "category = 'accounts'", "last_accessed DESC", 15
|
344
|
-
# Project.find_all ["category = ?", category_name], "created ASC", [
|
352
|
+
# Project.find_all ["category = ?", category_name], "created ASC", [15, 20]
|
345
353
|
def find_all(conditions = nil, orderings = nil, limit = nil, joins = nil)
|
346
354
|
sql = "SELECT * FROM #{table_name} "
|
347
355
|
sql << "#{joins} " if joins
|
348
356
|
add_conditions!(sql, conditions)
|
349
357
|
sql << "ORDER BY #{orderings} " unless orderings.nil?
|
350
358
|
|
351
|
-
|
359
|
+
limit = sanitize_sql(limit) if limit.is_a? Array and limit.first.is_a? String
|
360
|
+
connection.add_limit!(sql, limit) if limit
|
352
361
|
|
353
362
|
find_by_sql(sql)
|
354
363
|
end
|
@@ -522,7 +531,7 @@ module ActiveRecord #:nodoc:
|
|
522
531
|
# "mice" table. Example:
|
523
532
|
#
|
524
533
|
# class Mouse < ActiveRecord::Base
|
525
|
-
#
|
534
|
+
# set_table_name "mice"
|
526
535
|
# end
|
527
536
|
def table_name
|
528
537
|
table_name_prefix + undecorated_table_name(class_name_of_active_record_descendant(self)) + table_name_suffix
|
@@ -889,6 +898,9 @@ module ActiveRecord #:nodoc:
|
|
889
898
|
read_attribute(self.class.primary_key)
|
890
899
|
end
|
891
900
|
|
901
|
+
# Enables Active Record objects to be used as URL parameters in Action Pack automatically.
|
902
|
+
alias_method :to_param, :id
|
903
|
+
|
892
904
|
def id_before_type_cast #:nodoc:
|
893
905
|
read_attribute_before_type_cast(self.class.primary_key)
|
894
906
|
end
|
@@ -1012,6 +1024,7 @@ module ActiveRecord #:nodoc:
|
|
1012
1024
|
# attributes not included in that won't be allowed to be mass-assigned.
|
1013
1025
|
def attributes=(attributes)
|
1014
1026
|
return if attributes.nil?
|
1027
|
+
attributes.stringify_keys!
|
1015
1028
|
|
1016
1029
|
multi_parameter_attributes = []
|
1017
1030
|
remove_attributes_protected_from_mass_assignment(attributes).each do |k, v|
|
@@ -1233,7 +1246,7 @@ module ActiveRecord #:nodoc:
|
|
1233
1246
|
def attributes_with_quotes(include_primary_key = true)
|
1234
1247
|
columns_hash = self.class.columns_hash
|
1235
1248
|
|
1236
|
-
attrs_quoted =
|
1249
|
+
attrs_quoted = attributes.inject({}) do |attrs_quoted, pair|
|
1237
1250
|
attrs_quoted[pair.first] = quote(pair.last, columns_hash[pair.first]) unless !include_primary_key && pair.first == self.class.primary_key
|
1238
1251
|
attrs_quoted
|
1239
1252
|
end
|
@@ -78,6 +78,10 @@ module ActiveRecord
|
|
78
78
|
# you want to ensure that a certain callback is called for the entire hierarchy and the regular overwriteable methods when you
|
79
79
|
# want to leave it up to each descendent to decide whether they want to call +super+ and trigger the inherited callbacks.
|
80
80
|
#
|
81
|
+
# *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the callbacks before specifying the
|
82
|
+
# associations. Otherwise, you might trigger the loading of a child before the parent has registered the callbacks and they won't
|
83
|
+
# be inherited.
|
84
|
+
#
|
81
85
|
# == Types of callbacks
|
82
86
|
#
|
83
87
|
# There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects,
|
@@ -117,7 +121,7 @@ module ActiveRecord
|
|
117
121
|
# record.credit_card_number = decrypt(record.credit_card_number)
|
118
122
|
# end
|
119
123
|
#
|
120
|
-
# alias_method :
|
124
|
+
# alias_method :after_find, :after_save
|
121
125
|
#
|
122
126
|
# private
|
123
127
|
# def encrypt(value)
|
@@ -151,8 +155,8 @@ module ActiveRecord
|
|
151
155
|
#
|
152
156
|
# Because after_find and after_initialize is called for each object instantiated found by a finder, such as Base.find_all, we've had
|
153
157
|
# to implement a simple performance constraint (50% more speed on a simple test case). Unlike all the other callbacks, after_find and
|
154
|
-
# after_initialize
|
155
|
-
#
|
158
|
+
# after_initialize will only be run if an explicit implementation is defined (<tt>def after_find</tt>). In that case, all of the
|
159
|
+
# callback types will be called.
|
156
160
|
#
|
157
161
|
# == Cancelling callbacks
|
158
162
|
#
|
@@ -209,8 +213,19 @@ module ActiveRecord
|
|
209
213
|
module ClassMethods #:nodoc:
|
210
214
|
def instantiate_with_callbacks(record)
|
211
215
|
object = instantiate_without_callbacks(record)
|
212
|
-
|
213
|
-
object.send(:
|
216
|
+
|
217
|
+
if object.send(:respond_to_without_attributes?, :after_find)
|
218
|
+
object.send(:callback, :after_find)
|
219
|
+
else
|
220
|
+
object.send(:invoke_and_notify, :after_find)
|
221
|
+
end
|
222
|
+
|
223
|
+
if object.send(:respond_to_without_attributes?, :after_initialize)
|
224
|
+
object.send(:callback, :after_initialize)
|
225
|
+
else
|
226
|
+
object.send(:invoke_and_notify, :after_initialize)
|
227
|
+
end
|
228
|
+
|
214
229
|
object
|
215
230
|
end
|
216
231
|
end
|
@@ -223,7 +238,7 @@ module ActiveRecord
|
|
223
238
|
def initialize_with_callbacks(attributes = nil) #:nodoc:
|
224
239
|
initialize_without_callbacks(attributes)
|
225
240
|
result = yield self if block_given?
|
226
|
-
invoke_and_notify(:after_initialize)
|
241
|
+
respond_to_without_attributes?(:after_initialize) ? callback(:after_initialize) : invoke_and_notify(:after_initialize)
|
227
242
|
result
|
228
243
|
end
|
229
244
|
|
@@ -179,7 +179,7 @@ module ActiveRecord
|
|
179
179
|
case type
|
180
180
|
when :string then value
|
181
181
|
when :text then value
|
182
|
-
when :integer then value.to_i
|
182
|
+
when :integer then value.to_i rescue value ? 1 : 0
|
183
183
|
when :float then value.to_f
|
184
184
|
when :datetime then string_to_time(value)
|
185
185
|
when :timestamp then string_to_time(value)
|
@@ -353,13 +353,25 @@ module ActiveRecord
|
|
353
353
|
def structure_dump() end
|
354
354
|
|
355
355
|
def add_limit!(sql, limit)
|
356
|
+
if limit.is_a? Array
|
357
|
+
limit, offset = *limit
|
358
|
+
add_limit_with_offset!(sql, limit.to_i, offset.to_i)
|
359
|
+
else
|
360
|
+
add_limit_without_offset!(sql, limit)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def add_limit_with_offset!(sql, limit, offset)
|
365
|
+
sql << " LIMIT #{limit} OFFSET #{offset}"
|
366
|
+
end
|
367
|
+
|
368
|
+
def add_limit_without_offset!(sql, limit)
|
356
369
|
sql << " LIMIT #{limit}"
|
357
370
|
end
|
358
371
|
|
359
|
-
|
360
372
|
def initialize_schema_information
|
361
373
|
begin
|
362
|
-
execute "CREATE TABLE schema_info (version #{native_database_types[:integer]})"
|
374
|
+
execute "CREATE TABLE schema_info (version #{native_database_types[:integer][:name]}#{native_database_types[:integer][:limit]})"
|
363
375
|
insert "INSERT INTO schema_info (version) VALUES(0)"
|
364
376
|
rescue ActiveRecord::StatementInvalid
|
365
377
|
# Schema has been intialized
|
@@ -377,8 +389,9 @@ module ActiveRecord
|
|
377
389
|
end
|
378
390
|
|
379
391
|
def add_column(table_name, column_name, type, options = {})
|
380
|
-
|
381
|
-
add_column_sql
|
392
|
+
native_type = native_database_types[type]
|
393
|
+
add_column_sql = "ALTER TABLE #{table_name} ADD #{column_name} #{native_type[:name]}"
|
394
|
+
add_column_sql << "(#{options[:limit] || native_type[:limit]})" if options[:limit] || native_type[:limit]
|
382
395
|
add_column_sql << " DEFAULT '#{options[:default]}'" if options[:default]
|
383
396
|
execute(add_column_sql)
|
384
397
|
end
|
@@ -404,7 +417,7 @@ module ActiveRecord
|
|
404
417
|
log_info(sql, name, 0)
|
405
418
|
nil
|
406
419
|
end
|
407
|
-
rescue => e
|
420
|
+
rescue Exception => e
|
408
421
|
log_info("#{e.message}: #{sql}", name, 0)
|
409
422
|
raise ActiveRecord::StatementInvalid, "#{e.message}: #{sql}"
|
410
423
|
end
|
@@ -452,4 +465,4 @@ module ActiveRecord
|
|
452
465
|
end
|
453
466
|
end
|
454
467
|
end
|
455
|
-
end
|
468
|
+
end
|
@@ -89,7 +89,11 @@ begin
|
|
89
89
|
s.gsub(/'/, "''") # ' (for ruby-mode)
|
90
90
|
end
|
91
91
|
|
92
|
-
def
|
92
|
+
def add_limit_with_offset!(sql, limit, offset)
|
93
|
+
raise ArgumentError, 'add_limit_with_offset! not implemented'
|
94
|
+
end
|
95
|
+
|
96
|
+
def add_limit_without_offset!(sql, limit)
|
93
97
|
sql << " FETCH FIRST #{limit} ROWS ONLY"
|
94
98
|
end
|
95
99
|
|
@@ -67,16 +67,16 @@ module ActiveRecord
|
|
67
67
|
def native_database_types
|
68
68
|
{
|
69
69
|
:primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY",
|
70
|
-
:string => "varchar
|
71
|
-
:text => "text",
|
72
|
-
:integer => "int
|
73
|
-
:float => "float",
|
74
|
-
:datetime => "datetime",
|
75
|
-
:timestamp => "datetime",
|
76
|
-
:time => "datetime",
|
77
|
-
:date => "date",
|
78
|
-
:binary => "blob",
|
79
|
-
:boolean => "tinyint
|
70
|
+
:string => { :name => "varchar", :limit => 255 },
|
71
|
+
:text => { :name => "text" },
|
72
|
+
:integer => { :name => "int", :limit => 11 },
|
73
|
+
:float => { :name => "float" },
|
74
|
+
:datetime => { :name => "datetime" },
|
75
|
+
:timestamp => { :name => "datetime" },
|
76
|
+
:time => { :name => "datetime" },
|
77
|
+
:date => { :name => "date" },
|
78
|
+
:binary => { :name => "blob" },
|
79
|
+
:boolean => { :name => "tinyint", :limit => 1 }
|
80
80
|
}
|
81
81
|
end
|
82
82
|
|
@@ -172,7 +172,11 @@ module ActiveRecord
|
|
172
172
|
structure += select_one("SHOW CREATE TABLE #{table.to_a.first.last}")["Create Table"] + ";\n\n"
|
173
173
|
end
|
174
174
|
end
|
175
|
-
|
175
|
+
|
176
|
+
def add_limit_with_offset!(sql, limit, offset)
|
177
|
+
sql << " LIMIT #{offset}, #{limit}"
|
178
|
+
end
|
179
|
+
|
176
180
|
def recreate_database(name)
|
177
181
|
drop_database(name)
|
178
182
|
create_database(name)
|
@@ -2,15 +2,15 @@
|
|
2
2
|
# 1. I had to redefine a method in ActiveRecord to make it possible to implement an autonumbering
|
3
3
|
# solution for oracle. It's implemented in a way that is intended to not break other adapters.
|
4
4
|
# 2. Default value support needs a patch to the OCI8 driver, to enable it to read LONG columns.
|
5
|
-
#
|
6
|
-
# A similar patch is needed for TIMESTAMP.
|
7
|
-
#
|
5
|
+
# The driver-author has said he will add this in a future release.
|
6
|
+
# A similar patch is needed for TIMESTAMP. This should be replaced with the 0.2 version of the
|
7
|
+
# driver, which will support TIMESTAMP properly.
|
8
8
|
# 3. Large Object support works by an after_save callback added to the ActiveRecord. This is not
|
9
9
|
# a problem - you can add other (chained) after_save callbacks.
|
10
|
-
# 4. LIMIT and OFFSET work
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
10
|
+
# 4. LIMIT and OFFSET now work using a select from select from select. This pattern enables
|
11
|
+
# the middle select to limit downwards as much as possible, before the outermost select
|
12
|
+
# limits upwards. The extra rownum column is stripped from the results.
|
13
|
+
# See http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:127412348064
|
14
14
|
#
|
15
15
|
# Do what you want with this code, at your own peril, but if any significant portion of my code
|
16
16
|
# remains then please acknowledge my contribution.
|
@@ -118,13 +118,17 @@ begin
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def select_all(sql, name = nil)
|
121
|
-
offset = sql =~ /OFFSET (\d+)$/ ? $1.to_i :
|
121
|
+
offset = sql =~ /OFFSET (\d+)$/ ? $1.to_i : 0
|
122
122
|
sql, limit = $1, $2.to_i if sql =~ /(.*)(?: LIMIT[= ](\d+))(\s*OFFSET \d+)?$/
|
123
|
+
if limit
|
124
|
+
sql = "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_ where rownum <= #{offset+limit}) where raw_rnum_ > #{offset}"
|
125
|
+
elsif offset > 0
|
126
|
+
sql = "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_) where raw_rnum_ > #{offset}"
|
127
|
+
end
|
123
128
|
cursor = log(sql, name, @connection) { @connection.exec sql }
|
124
129
|
cols = cursor.get_col_names.map { |x| x.downcase }
|
125
130
|
rows = []
|
126
131
|
while row = cursor.fetch
|
127
|
-
next if cursor.row_count <= offset
|
128
132
|
hash = Hash.new
|
129
133
|
cols.each_with_index { |col, i|
|
130
134
|
hash[col] = case row[i]
|
@@ -134,10 +138,9 @@ begin
|
|
134
138
|
(row[i].hour == 0 and row[i].minute == 0 and row[i].second == 0) ?
|
135
139
|
row[i].to_date : row[i].to_time
|
136
140
|
else row[i]
|
137
|
-
end
|
141
|
+
end unless col == 'raw_rnum_'
|
138
142
|
}
|
139
143
|
rows << hash
|
140
|
-
break if rows.size == limit
|
141
144
|
end
|
142
145
|
rows
|
143
146
|
ensure
|
@@ -179,10 +182,6 @@ begin
|
|
179
182
|
alias :update :execute
|
180
183
|
alias :delete :execute
|
181
184
|
|
182
|
-
def add_limit!(sql, limit)
|
183
|
-
sql << "LIMIT=" << limit.to_s
|
184
|
-
end
|
185
|
-
|
186
185
|
def begin_db_transaction()
|
187
186
|
@connection.autocommit = false
|
188
187
|
end
|
@@ -253,19 +253,12 @@ EOL
|
|
253
253
|
"[#{name}]"
|
254
254
|
end
|
255
255
|
|
256
|
-
def
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
order_by = sql.include?("ORDER BY") ? get_order_by(sql.sub(/.*ORDER\sBY./, "")) : nil
|
263
|
-
if limit_amount.size == 2
|
264
|
-
sql.gsub!(/SELECT/i, "SELECT * FROM ( SELECT TOP #{limit_amount[0]} * FROM ( SELECT TOP #{limit_amount[1]}")<<" ) AS tmp1 ORDER BY #{order_by[1]} ) AS tmp2 ORDER BY #{order_by[0]}"
|
265
|
-
else
|
266
|
-
sql.gsub!(/SELECT/i, "SELECT TOP #{limit_amount[0]}")
|
267
|
-
end
|
268
|
-
end
|
256
|
+
def add_limit_with_offset!(sql, limit, offset)
|
257
|
+
raise ArgumentError, 'add_limit_with_offset! not implemented'
|
258
|
+
end
|
259
|
+
|
260
|
+
def add_limit_without_offset!(sql, limit)
|
261
|
+
raise ArgumentError, 'add_limit_without_offset! not implemented'
|
269
262
|
end
|
270
263
|
|
271
264
|
def recreate_database(name)
|
@@ -121,6 +121,14 @@ require 'csv'
|
|
121
121
|
# from a CSV fixture file would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual
|
122
122
|
# fixtures available as instance variables @web_site_1 and @web_site_2.
|
123
123
|
#
|
124
|
+
# If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options.
|
125
|
+
#
|
126
|
+
# - to completely disable instantiated fixtures:
|
127
|
+
# self.use_instantiated_fixtures = false
|
128
|
+
#
|
129
|
+
# - to keep the fixture instance (@web_sites) available, but do not automatically 'find' each instance:
|
130
|
+
# self.use_instantiated_fixtures = :no_instances
|
131
|
+
#
|
124
132
|
# = Dynamic fixtures with ERb
|
125
133
|
#
|
126
134
|
# Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
|
@@ -164,6 +172,9 @@ require 'csv'
|
|
164
172
|
# If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
|
165
173
|
# then you may omit all fixtures declarations in your test cases since all the data's already there and every case rolls back its changes.
|
166
174
|
#
|
175
|
+
# In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide
|
176
|
+
# access to fixture data for every table that has been loaded through fixtures (depending on the value of +use_instantiated_fixtures+)
|
177
|
+
#
|
167
178
|
# When *not* to use transactional fixtures:
|
168
179
|
# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit,
|
169
180
|
# particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify
|
@@ -173,14 +184,25 @@ require 'csv'
|
|
173
184
|
class Fixtures < Hash
|
174
185
|
DEFAULT_FILTER_RE = /\.ya?ml$/
|
175
186
|
|
176
|
-
def self.instantiate_fixtures(object, table_name, fixtures)
|
187
|
+
def self.instantiate_fixtures(object, table_name, fixtures, load_instances=true)
|
177
188
|
object.instance_variable_set "@#{table_name}", fixtures
|
178
|
-
|
179
|
-
|
180
|
-
|
189
|
+
if load_instances
|
190
|
+
fixtures.each do |name, fixture|
|
191
|
+
if model = fixture.find
|
192
|
+
object.instance_variable_set "@#{name}", model
|
193
|
+
end
|
181
194
|
end
|
182
195
|
end
|
183
196
|
end
|
197
|
+
|
198
|
+
def self.instantiate_all_loaded_fixtures(object, load_instances=true)
|
199
|
+
all_loaded_fixtures.each do |table_name, fixtures|
|
200
|
+
Fixtures.instantiate_fixtures(object, table_name, fixtures, load_instances)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
cattr_accessor :all_loaded_fixtures
|
205
|
+
self.all_loaded_fixtures = {}
|
184
206
|
|
185
207
|
def self.create_fixtures(fixtures_directory, *table_names)
|
186
208
|
connection = block_given? ? yield : ActiveRecord::Base.connection
|
@@ -189,15 +211,17 @@ class Fixtures < Hash
|
|
189
211
|
begin
|
190
212
|
ActiveRecord::Base.logger.level = Logger::ERROR
|
191
213
|
|
214
|
+
fixtures_map = {}
|
192
215
|
fixtures = table_names.flatten.map do |table_name|
|
193
|
-
Fixtures.new(connection, File.split(table_name.to_s).last, File.join(fixtures_directory, table_name.to_s))
|
194
|
-
end
|
195
|
-
|
216
|
+
fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, File.join(fixtures_directory, table_name.to_s))
|
217
|
+
end
|
218
|
+
all_loaded_fixtures.merge! fixtures_map
|
219
|
+
|
196
220
|
connection.transaction do
|
197
221
|
fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
|
198
222
|
fixtures.each { |fixture| fixture.insert_fixtures }
|
199
223
|
end
|
200
|
-
|
224
|
+
|
201
225
|
reset_sequences(connection, table_names) if connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
202
226
|
|
203
227
|
return fixtures.size > 1 ? fixtures : fixtures.first
|
@@ -360,19 +384,21 @@ module Test #:nodoc:
|
|
360
384
|
cattr_accessor :fixture_path
|
361
385
|
class_inheritable_accessor :fixture_table_names
|
362
386
|
class_inheritable_accessor :use_transactional_fixtures
|
363
|
-
class_inheritable_accessor :use_instantiated_fixtures
|
387
|
+
class_inheritable_accessor :use_instantiated_fixtures # true, false, or :no_instances
|
388
|
+
class_inheritable_accessor :pre_loaded_fixtures
|
364
389
|
|
365
390
|
self.fixture_table_names = []
|
366
391
|
self.use_transactional_fixtures = false
|
367
392
|
self.use_instantiated_fixtures = true
|
393
|
+
self.pre_loaded_fixtures = false
|
368
394
|
|
369
395
|
def self.fixtures(*table_names)
|
370
|
-
self.fixture_table_names
|
396
|
+
self.fixture_table_names |= table_names.flatten
|
371
397
|
require_fixture_classes
|
372
398
|
end
|
373
399
|
|
374
|
-
def self.require_fixture_classes
|
375
|
-
fixture_table_names.each do |table_name|
|
400
|
+
def self.require_fixture_classes(table_names=nil)
|
401
|
+
(table_names || fixture_table_names).each do |table_name|
|
376
402
|
begin
|
377
403
|
require Inflector.singularize(table_name.to_s)
|
378
404
|
rescue LoadError
|
@@ -382,6 +408,10 @@ module Test #:nodoc:
|
|
382
408
|
end
|
383
409
|
|
384
410
|
def setup_with_fixtures
|
411
|
+
if pre_loaded_fixtures && !use_transactional_fixtures
|
412
|
+
raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
|
413
|
+
end
|
414
|
+
|
385
415
|
# Load fixtures once and begin transaction.
|
386
416
|
if use_transactional_fixtures
|
387
417
|
load_fixtures unless @already_loaded_fixtures
|
@@ -438,13 +468,29 @@ module Test #:nodoc:
|
|
438
468
|
@loaded_fixtures[table_name] = Fixtures.create_fixtures(fixture_path, table_name)
|
439
469
|
end
|
440
470
|
end
|
441
|
-
|
471
|
+
|
472
|
+
# for pre_loaded_fixtures, only require the classes once. huge speed improvement
|
473
|
+
@@required_fixture_classes = false
|
474
|
+
|
442
475
|
def instantiate_fixtures
|
443
|
-
|
444
|
-
|
445
|
-
|
476
|
+
if pre_loaded_fixtures
|
477
|
+
raise RuntimeError, 'Load fixtures before instantiating them.' if Fixtures.all_loaded_fixtures.empty?
|
478
|
+
unless @@required_fixture_classes
|
479
|
+
self.class.require_fixture_classes Fixtures.all_loaded_fixtures.keys
|
480
|
+
@@required_fixture_classes = true
|
481
|
+
end
|
482
|
+
Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
|
483
|
+
else
|
484
|
+
raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
|
485
|
+
@loaded_fixtures.each do |table_name, fixtures|
|
486
|
+
Fixtures.instantiate_fixtures(self, table_name, fixtures, load_instances?)
|
487
|
+
end
|
446
488
|
end
|
447
489
|
end
|
490
|
+
|
491
|
+
def load_instances?
|
492
|
+
use_instantiated_fixtures != :no_instances
|
493
|
+
end
|
448
494
|
end
|
449
495
|
|
450
496
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module ActiveRecord
|
2
|
-
class IrreversibleMigration < ActiveRecordError
|
2
|
+
class IrreversibleMigration < ActiveRecordError#:nodoc:
|
3
3
|
end
|
4
4
|
|
5
|
-
class Migration
|
5
|
+
class Migration #:nodoc:
|
6
6
|
class << self
|
7
7
|
def up() end
|
8
8
|
def down() end
|
@@ -14,7 +14,7 @@ module ActiveRecord
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
class Migrator
|
17
|
+
class Migrator#:nodoc:
|
18
18
|
class << self
|
19
19
|
def up(migrations_path, target_version = nil)
|
20
20
|
new(:up, migrations_path, target_version).migrate
|
@@ -270,11 +270,11 @@ module ActiveRecord
|
|
270
270
|
def validates_confirmation_of(*attr_names)
|
271
271
|
configuration = { :message => ActiveRecord::Errors.default_error_messages[:confirmation], :on => :save }
|
272
272
|
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
273
|
-
configuration[:message].gsub!(/\"/, '\\\\\"')
|
274
273
|
|
275
|
-
|
276
|
-
|
277
|
-
|
274
|
+
attr_accessor *(attr_names.map { |n| "#{n}_confirmation" })
|
275
|
+
|
276
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
277
|
+
record.errors.add(attr_name, configuration[:message]) unless record.send("#{attr_name}_confirmation").nil? or value == record.send("#{attr_name}_confirmation")
|
278
278
|
end
|
279
279
|
end
|
280
280
|
|
@@ -294,13 +294,13 @@ module ActiveRecord
|
|
294
294
|
#
|
295
295
|
# NOTE: The agreement is considered valid if it's set to the string "1". This makes it easy to relate it to an HTML checkbox.
|
296
296
|
def validates_acceptance_of(*attr_names)
|
297
|
-
configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save }
|
297
|
+
configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save, :allow_nil => true }
|
298
298
|
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
299
|
-
configuration[:message].gsub!(/\"/, '\\\\\"')
|
300
299
|
|
301
|
-
|
302
|
-
|
303
|
-
|
300
|
+
attr_accessor *attr_names
|
301
|
+
|
302
|
+
validates_each(attr_names,configuration) do |record, attr_name, value|
|
303
|
+
record.errors.add(attr_name, configuration[:message]) unless value == "1"
|
304
304
|
end
|
305
305
|
end
|
306
306
|
|
@@ -312,10 +312,13 @@ module ActiveRecord
|
|
312
312
|
def validates_presence_of(*attr_names)
|
313
313
|
configuration = { :message => ActiveRecord::Errors.default_error_messages[:empty], :on => :save }
|
314
314
|
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
315
|
-
configuration[:message].gsub!(/\"/, '\\\\\"')
|
316
315
|
|
317
|
-
|
318
|
-
|
316
|
+
# can't use validates_each here, because it cannot cope with non-existant attributes,
|
317
|
+
# while errors.add_on_empty can
|
318
|
+
attr_names.each do |attr_name|
|
319
|
+
send(validation_method(configuration[:on])) do |record|
|
320
|
+
record.errors.add_on_empty(attr_name,configuration[:message])
|
321
|
+
end
|
319
322
|
end
|
320
323
|
end
|
321
324
|
|
@@ -414,13 +417,14 @@ module ActiveRecord
|
|
414
417
|
def validates_uniqueness_of(*attr_names)
|
415
418
|
configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken] }
|
416
419
|
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
417
|
-
configuration[:message].gsub!(/\"/, '\\\\\"')
|
418
420
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
421
|
+
if scope = configuration[:scope]
|
422
|
+
validates_each(attr_names,configuration) do |record, attr_name, value|
|
423
|
+
record.errors.add(attr_name, configuration[:message]) if record.class.find_first(record.new_record? ? ["#{attr_name} = ? AND #{scope} = ?", record.send(attr_name), record.send(scope)] : ["#{attr_name} = ? AND #{record.class.primary_key} <> ? AND #{scope} = ?", record.send(attr_name), record.send(:id), record.send(scope)])
|
424
|
+
end
|
425
|
+
else
|
426
|
+
validates_each(attr_names,configuration) do |record, attr_name, value|
|
427
|
+
record.errors.add(attr_name, configuration[:message]) if record.class.find_first(record.new_record? ? ["#{attr_name} = ?", record.send(attr_name)] : ["#{attr_name} = ? AND #{record.class.primary_key} <> ?", record.send(attr_name), record.send(:id) ] )
|
424
428
|
end
|
425
429
|
end
|
426
430
|
end
|
@@ -441,12 +445,11 @@ module ActiveRecord
|
|
441
445
|
def validates_format_of(*attr_names)
|
442
446
|
configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save, :with => nil }
|
443
447
|
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
444
|
-
configuration[:message].gsub!(/\"/, '\\\\\"')
|
445
448
|
|
446
449
|
raise(ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash") unless configuration[:with].is_a?(Regexp)
|
447
450
|
|
448
|
-
|
449
|
-
|
451
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
452
|
+
record.errors.add(attr_name, configuration[:message]) unless value.to_s =~ configuration[:with]
|
450
453
|
end
|
451
454
|
end
|
452
455
|
|
@@ -464,19 +467,13 @@ module ActiveRecord
|
|
464
467
|
def validates_inclusion_of(*attr_names)
|
465
468
|
configuration = { :message => ActiveRecord::Errors.default_error_messages[:inclusion], :on => :save }
|
466
469
|
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
467
|
-
|
468
|
-
|
470
|
+
|
469
471
|
enum = configuration[:in] || configuration[:within]
|
470
|
-
|
471
|
-
|
472
|
+
|
472
473
|
raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?")
|
473
474
|
|
474
|
-
|
475
|
-
|
476
|
-
class_eval(%(#{validation_method(configuration[:on])} %{errors.add("#{attr_name}", "#{configuration[:message]}") unless #{attr_name}.nil? or (#{enum.inspect}).include?(#{attr_name}) }))
|
477
|
-
else
|
478
|
-
class_eval(%(#{validation_method(configuration[:on])} %{errors.add("#{attr_name}", "#{configuration[:message]}") unless (#{enum.inspect}).include?(#{attr_name}) }))
|
479
|
-
end
|
475
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
476
|
+
record.errors.add(attr_name, configuration[:message]) unless enum.include?(value)
|
480
477
|
end
|
481
478
|
end
|
482
479
|
|
@@ -504,13 +501,10 @@ module ActiveRecord
|
|
504
501
|
def validates_associated(*attr_names)
|
505
502
|
configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save }
|
506
503
|
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
errors.add("#{attr_name}", "#{configuration[:message]}") unless
|
512
|
-
(#{attr_name}.is_a?(Array) ? #{attr_name} : [#{attr_name}]).inject(true){ |memo, record| (record.nil? or record.valid?) and memo }
|
513
|
-
}))
|
504
|
+
|
505
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
506
|
+
record.errors.add(attr_name, configuration[:message]) unless
|
507
|
+
(value.is_a?(Array) ? value : [value]).inject(true) { |memo, r| (r.nil? or r.valid?) and memo }
|
514
508
|
end
|
515
509
|
end
|
516
510
|
|
@@ -526,29 +520,25 @@ module ActiveRecord
|
|
526
520
|
# * <tt>message</tt> - A custom error message (default is: "is not a number")
|
527
521
|
# * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
|
528
522
|
# * <tt>only_integer</tt> Specifies whether the value has to be an integer, e.g. an integral value (default is false)
|
523
|
+
# * <tt>allow_nil</tt> Skip validation if attribute is nil (default is false). Notice that for fixnum and float columsn empty strings are converted to nil
|
529
524
|
def validates_numericality_of(*attr_names)
|
530
525
|
configuration = { :message => ActiveRecord::Errors.default_error_messages[:not_a_number], :on => :save,
|
531
|
-
:
|
526
|
+
:only_integer => false, :allow_nil => false }
|
532
527
|
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
533
528
|
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
# accept "099" and String#to_i accepts everything. The string containing the regexp is evaluated twice
|
538
|
-
# so we have to escape everything properly
|
539
|
-
class_eval(%(#{validation_method(configuration[:on])} %{
|
540
|
-
errors.add("#{attr_name}", "#{configuration[:message]}") unless #{attr_name}_before_type_cast.to_s =~ /^[\\\\+\\\\-]?\\\\d+$/
|
541
|
-
}))
|
542
|
-
else
|
543
|
-
class_eval(%(#{validation_method(configuration[:on])} %{
|
544
|
-
begin
|
545
|
-
Kernel.Float(#{attr_name}_before_type_cast)
|
546
|
-
rescue ArgumentError, TypeError
|
547
|
-
errors.add("#{attr_name}", "#{configuration[:message]}")
|
548
|
-
end
|
549
|
-
}))
|
529
|
+
if configuration[:only_integer]
|
530
|
+
validates_each(attr_names,configuration) do |record, attr_name,value|
|
531
|
+
record.errors.add(attr_name, configuration[:message]) unless record.send("#{attr_name}_before_type_cast").to_s =~ /^[+-]?\d+$/
|
550
532
|
end
|
551
|
-
|
533
|
+
else
|
534
|
+
validates_each(attr_names,configuration) do |record, attr_name,value|
|
535
|
+
begin
|
536
|
+
Kernel.Float(record.send("#{attr_name}_before_type_cast").to_s)
|
537
|
+
rescue ArgumentError, TypeError
|
538
|
+
record.errors.add(attr_name, configuration[:message])
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
552
542
|
end
|
553
543
|
|
554
544
|
private
|
data/rakefile
CHANGED
@@ -8,7 +8,7 @@ require 'rake/contrib/rubyforgepublisher'
|
|
8
8
|
|
9
9
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
10
10
|
PKG_NAME = 'activerecord'
|
11
|
-
PKG_VERSION = '1.
|
11
|
+
PKG_VERSION = '1.9.0' + PKG_BUILD
|
12
12
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
13
13
|
|
14
14
|
PKG_FILES = FileList[
|
@@ -117,7 +117,7 @@ spec = Gem::Specification.new do |s|
|
|
117
117
|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
118
118
|
end
|
119
119
|
|
120
|
-
s.add_dependency('activesupport', '= 1.0.
|
120
|
+
s.add_dependency('activesupport', '= 1.0.2' + PKG_BUILD)
|
121
121
|
|
122
122
|
s.files.delete "test/fixtures/fixture_database.sqlite"
|
123
123
|
s.files.delete "test/fixtures/fixture_database_2.sqlite"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
|
3
|
+
class ActiveSchemaTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
|
6
|
+
alias_method :real_execute, :execute
|
7
|
+
def execute(sql, name = nil) return sql end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:alias_method, :execute, :real_execute)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_drop_table
|
16
|
+
assert_equal "DROP TABLE people", drop_table(:people)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_add_column
|
20
|
+
assert_equal "ALTER TABLE people ADD last_name varchar(255)", add_column(:people, :last_name, :string)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_add_column_with_limit
|
24
|
+
assert_equal "ALTER TABLE people ADD key varchar(32)", add_column(:people, :key, :string, :limit => 32)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def method_missing(method_symbol, *arguments)
|
29
|
+
ActiveRecord::Base.connection.send(method_symbol, *arguments)
|
30
|
+
end
|
31
|
+
end
|
data/test/callbacks_test.rb
CHANGED
@@ -41,14 +41,11 @@ class CallbackDeveloper < ActiveRecord::Base
|
|
41
41
|
@history ||= []
|
42
42
|
end
|
43
43
|
|
44
|
-
# after_initialize and after_find
|
45
|
-
# They are invoked only if instance methods have been defined.
|
44
|
+
# after_initialize and after_find are invoked only if instance methods have been defined.
|
46
45
|
def after_initialize
|
47
|
-
history << [:after_initialize, :method]
|
48
46
|
end
|
49
47
|
|
50
48
|
def after_find
|
51
|
-
history << [:after_find, :method]
|
52
49
|
end
|
53
50
|
end
|
54
51
|
|
@@ -61,15 +58,24 @@ class CallbacksTest < Test::Unit::TestCase
|
|
61
58
|
def test_initialize
|
62
59
|
david = CallbackDeveloper.new
|
63
60
|
assert_equal [
|
64
|
-
[ :after_initialize, :
|
61
|
+
[ :after_initialize, :string ],
|
62
|
+
[ :after_initialize, :proc ],
|
63
|
+
[ :after_initialize, :object ],
|
64
|
+
[ :after_initialize, :block ],
|
65
65
|
], david.history
|
66
66
|
end
|
67
67
|
|
68
68
|
def test_find
|
69
69
|
david = CallbackDeveloper.find(1)
|
70
70
|
assert_equal [
|
71
|
-
[ :after_find,
|
72
|
-
[ :
|
71
|
+
[ :after_find, :string ],
|
72
|
+
[ :after_find, :proc ],
|
73
|
+
[ :after_find, :object ],
|
74
|
+
[ :after_find, :block ],
|
75
|
+
[ :after_initialize, :string ],
|
76
|
+
[ :after_initialize, :proc ],
|
77
|
+
[ :after_initialize, :object ],
|
78
|
+
[ :after_initialize, :block ],
|
73
79
|
], david.history
|
74
80
|
end
|
75
81
|
|
@@ -77,7 +83,10 @@ class CallbacksTest < Test::Unit::TestCase
|
|
77
83
|
david = CallbackDeveloper.new
|
78
84
|
david.valid?
|
79
85
|
assert_equal [
|
80
|
-
[ :after_initialize, :
|
86
|
+
[ :after_initialize, :string ],
|
87
|
+
[ :after_initialize, :proc ],
|
88
|
+
[ :after_initialize, :object ],
|
89
|
+
[ :after_initialize, :block ],
|
81
90
|
[ :before_validation, :string ],
|
82
91
|
[ :before_validation, :proc ],
|
83
92
|
[ :before_validation, :object ],
|
@@ -101,8 +110,14 @@ class CallbacksTest < Test::Unit::TestCase
|
|
101
110
|
david = CallbackDeveloper.find(1)
|
102
111
|
david.valid?
|
103
112
|
assert_equal [
|
104
|
-
[ :after_find,
|
105
|
-
[ :
|
113
|
+
[ :after_find, :string ],
|
114
|
+
[ :after_find, :proc ],
|
115
|
+
[ :after_find, :object ],
|
116
|
+
[ :after_find, :block ],
|
117
|
+
[ :after_initialize, :string ],
|
118
|
+
[ :after_initialize, :proc ],
|
119
|
+
[ :after_initialize, :object ],
|
120
|
+
[ :after_initialize, :block ],
|
106
121
|
[ :before_validation, :string ],
|
107
122
|
[ :before_validation, :proc ],
|
108
123
|
[ :before_validation, :object ],
|
@@ -125,7 +140,10 @@ class CallbacksTest < Test::Unit::TestCase
|
|
125
140
|
def test_create
|
126
141
|
david = CallbackDeveloper.create('name' => 'David', 'salary' => 1000000)
|
127
142
|
assert_equal [
|
128
|
-
[ :after_initialize, :
|
143
|
+
[ :after_initialize, :string ],
|
144
|
+
[ :after_initialize, :proc ],
|
145
|
+
[ :after_initialize, :object ],
|
146
|
+
[ :after_initialize, :block ],
|
129
147
|
[ :before_validation, :string ],
|
130
148
|
[ :before_validation, :proc ],
|
131
149
|
[ :before_validation, :object ],
|
@@ -165,8 +183,14 @@ class CallbacksTest < Test::Unit::TestCase
|
|
165
183
|
david = CallbackDeveloper.find(1)
|
166
184
|
david.save
|
167
185
|
assert_equal [
|
168
|
-
[ :after_find,
|
169
|
-
[ :
|
186
|
+
[ :after_find, :string ],
|
187
|
+
[ :after_find, :proc ],
|
188
|
+
[ :after_find, :object ],
|
189
|
+
[ :after_find, :block ],
|
190
|
+
[ :after_initialize, :string ],
|
191
|
+
[ :after_initialize, :proc ],
|
192
|
+
[ :after_initialize, :object ],
|
193
|
+
[ :after_initialize, :block ],
|
170
194
|
[ :before_validation, :string ],
|
171
195
|
[ :before_validation, :proc ],
|
172
196
|
[ :before_validation, :object ],
|
@@ -206,8 +230,14 @@ class CallbacksTest < Test::Unit::TestCase
|
|
206
230
|
david = CallbackDeveloper.find(1)
|
207
231
|
david.destroy
|
208
232
|
assert_equal [
|
209
|
-
[ :after_find,
|
210
|
-
[ :
|
233
|
+
[ :after_find, :string ],
|
234
|
+
[ :after_find, :proc ],
|
235
|
+
[ :after_find, :object ],
|
236
|
+
[ :after_find, :block ],
|
237
|
+
[ :after_initialize, :string ],
|
238
|
+
[ :after_initialize, :proc ],
|
239
|
+
[ :after_initialize, :object ],
|
240
|
+
[ :after_initialize, :block ],
|
211
241
|
[ :before_destroy, :string ],
|
212
242
|
[ :before_destroy, :proc ],
|
213
243
|
[ :before_destroy, :object ],
|
@@ -223,8 +253,14 @@ class CallbacksTest < Test::Unit::TestCase
|
|
223
253
|
david = CallbackDeveloper.find(1)
|
224
254
|
CallbackDeveloper.delete(david.id)
|
225
255
|
assert_equal [
|
226
|
-
[ :after_find,
|
227
|
-
[ :
|
256
|
+
[ :after_find, :string ],
|
257
|
+
[ :after_find, :proc ],
|
258
|
+
[ :after_find, :object ],
|
259
|
+
[ :after_find, :block ],
|
260
|
+
[ :after_initialize, :string ],
|
261
|
+
[ :after_initialize, :proc ],
|
262
|
+
[ :after_initialize, :object ],
|
263
|
+
[ :after_initialize, :block ],
|
228
264
|
], david.history
|
229
265
|
end
|
230
266
|
|
@@ -234,8 +270,14 @@ class CallbacksTest < Test::Unit::TestCase
|
|
234
270
|
CallbackDeveloper.before_validation proc { |model| model.history << [:before_validation, :should_never_get_here] }
|
235
271
|
david.save
|
236
272
|
assert_equal [
|
237
|
-
[ :after_find,
|
238
|
-
[ :
|
273
|
+
[ :after_find, :string ],
|
274
|
+
[ :after_find, :proc ],
|
275
|
+
[ :after_find, :object ],
|
276
|
+
[ :after_find, :block ],
|
277
|
+
[ :after_initialize, :string ],
|
278
|
+
[ :after_initialize, :proc ],
|
279
|
+
[ :after_initialize, :object ],
|
280
|
+
[ :after_initialize, :block ],
|
239
281
|
[ :before_validation, :string ],
|
240
282
|
[ :before_validation, :proc ],
|
241
283
|
[ :before_validation, :object ],
|
@@ -13,7 +13,7 @@ sqlite_test_db2 = "#{BASE_DIR}/fixture_database_2.sqlite"
|
|
13
13
|
def make_connection(clazz, db_file, db_definitions_file)
|
14
14
|
unless File.exist?(db_file)
|
15
15
|
puts "SQLite database not found at #{db_file}. Rebuilding it."
|
16
|
-
sqlite_command =
|
16
|
+
sqlite_command = %Q{sqlite #{db_file} "create table a (a integer); drop table a;"}
|
17
17
|
puts "Executing '#{sqlite_command}'"
|
18
18
|
raise SqliteError.new("Seems that there is no sqlite executable available") unless system(sqlite_command)
|
19
19
|
clazz.establish_connection(
|
@@ -13,7 +13,7 @@ sqlite_test_db2 = "#{BASE_DIR}/fixture_database_2.sqlite3"
|
|
13
13
|
def make_connection(clazz, db_file, db_definitions_file)
|
14
14
|
unless File.exist?(db_file)
|
15
15
|
puts "SQLite3 database not found at #{db_file}. Rebuilding it."
|
16
|
-
sqlite_command =
|
16
|
+
sqlite_command = %Q{sqlite3 #{db_file} "create table a (a integer); drop table a;"}
|
17
17
|
puts "Executing '#{sqlite_command}'"
|
18
18
|
raise SqliteError.new("Seems that there is no sqlite3 executable available") unless system(sqlite_command)
|
19
19
|
clazz.establish_connection(
|
data/test/finder_test.rb
CHANGED
@@ -4,12 +4,19 @@ require 'fixtures/topic'
|
|
4
4
|
require 'fixtures/entrant'
|
5
5
|
|
6
6
|
class FinderTest < Test::Unit::TestCase
|
7
|
-
fixtures :companies, :topics, :entrants
|
7
|
+
fixtures :companies, :topics, :entrants, :developers
|
8
8
|
|
9
9
|
def test_find
|
10
10
|
assert_equal(@topics["first"]["title"], Topic.find(1).title)
|
11
11
|
end
|
12
12
|
|
13
|
+
def test_exists
|
14
|
+
assert (Topic.exists?(1))
|
15
|
+
assert !(Topic.exists?(45))
|
16
|
+
assert !(Topic.exists?("foo"))
|
17
|
+
assert !(Topic.exists?([1,2]))
|
18
|
+
end
|
19
|
+
|
13
20
|
def test_find_by_array_of_one_id
|
14
21
|
assert_kind_of(Array, Topic.find([ 1 ]))
|
15
22
|
assert_equal(1, Topic.find([ 1 ]).length)
|
@@ -233,6 +240,37 @@ class FinderTest < Test::Unit::TestCase
|
|
233
240
|
assert_equal "Mary", topics[0].author_name
|
234
241
|
end
|
235
242
|
|
243
|
+
def test_find_with_bad_sql
|
244
|
+
assert_raises(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_find_all_with_limit
|
248
|
+
first_five_developers = Developer.find_all nil, 'id ASC', 5
|
249
|
+
assert_equal 5, first_five_developers.length
|
250
|
+
assert_equal 'David', first_five_developers.first.name
|
251
|
+
assert_equal 'fixture_5', first_five_developers.last.name
|
252
|
+
|
253
|
+
no_developers = Developer.find_all nil, 'id ASC', 0
|
254
|
+
assert_equal 0, no_developers.length
|
255
|
+
|
256
|
+
assert_equal first_five_developers, Developer.find_all(nil, 'id ASC', [5])
|
257
|
+
assert_equal no_developers, Developer.find_all(nil, 'id ASC', [0])
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_find_all_with_limit_and_offset
|
261
|
+
first_three_developers = Developer.find_all nil, 'id ASC', [3, 0]
|
262
|
+
second_three_developers = Developer.find_all nil, 'id ASC', [3, 3]
|
263
|
+
last_two_developers = Developer.find_all nil, 'id ASC', [3, 8]
|
264
|
+
|
265
|
+
assert_equal 3, first_three_developers.length
|
266
|
+
assert_equal 3, second_three_developers.length
|
267
|
+
assert_equal 2, last_two_developers.length
|
268
|
+
|
269
|
+
assert_equal 'David', first_three_developers.first.name
|
270
|
+
assert_equal 'fixture_4', second_three_developers.first.name
|
271
|
+
assert_equal 'fixture_9', last_two_developers.first.name
|
272
|
+
end
|
273
|
+
|
236
274
|
protected
|
237
275
|
def bind(statement, *vars)
|
238
276
|
if vars.first.is_a?(Hash)
|
Binary file
|
Binary file
|
data/test/fixtures_test.rb
CHANGED
@@ -113,8 +113,10 @@ class FixturesWithoutInstantiationTest < Test::Unit::TestCase
|
|
113
113
|
fixtures :topics, :developers, :accounts
|
114
114
|
|
115
115
|
def test_without_complete_instantiation
|
116
|
-
assert_nil @topics
|
117
116
|
assert_nil @first
|
117
|
+
assert_nil @topics
|
118
|
+
assert_nil @developers
|
119
|
+
assert_nil @accounts
|
118
120
|
end
|
119
121
|
|
120
122
|
def test_fixtures_from_root_yml_without_instantiation
|
@@ -123,6 +125,19 @@ class FixturesWithoutInstantiationTest < Test::Unit::TestCase
|
|
123
125
|
end
|
124
126
|
|
125
127
|
|
128
|
+
class FixturesWithoutInstanceInstantiationTest < Test::Unit::TestCase
|
129
|
+
self.use_instantiated_fixtures = :no_instances
|
130
|
+
fixtures :topics, :developers, :accounts
|
131
|
+
|
132
|
+
def test_without_instance_instantiation
|
133
|
+
assert_nil @first
|
134
|
+
assert_not_nil @topics
|
135
|
+
assert_not_nil @developers
|
136
|
+
assert_not_nil @accounts
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
|
126
141
|
class TransactionalFixturesTest < Test::Unit::TestCase
|
127
142
|
self.use_transactional_fixtures = true
|
128
143
|
fixtures :topics
|
@@ -136,3 +151,23 @@ class TransactionalFixturesTest < Test::Unit::TestCase
|
|
136
151
|
assert_not_nil @first
|
137
152
|
end
|
138
153
|
end
|
154
|
+
|
155
|
+
|
156
|
+
class MultipleFixturesTest < Test::Unit::TestCase
|
157
|
+
fixtures :topics
|
158
|
+
fixtures :developers, :accounts
|
159
|
+
|
160
|
+
def test_fixture_table_names
|
161
|
+
assert_equal([:topics, :developers, :accounts], fixture_table_names)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
class OverlappingFixturesTest < Test::Unit::TestCase
|
167
|
+
fixtures :topics, :developers
|
168
|
+
fixtures :developers, :accounts
|
169
|
+
|
170
|
+
def test_fixture_table_names
|
171
|
+
assert_equal([:topics, :developers, :accounts], fixture_table_names)
|
172
|
+
end
|
173
|
+
end
|
data/test/validations_test.rb
CHANGED
@@ -606,40 +606,40 @@ class ValidationsTest < Test::Unit::TestCase
|
|
606
606
|
end
|
607
607
|
|
608
608
|
def test_validates_numericality_of_with_string
|
609
|
-
Topic.validates_numericality_of( :
|
609
|
+
Topic.validates_numericality_of( :approved )
|
610
610
|
["not a number","42 not a number","0xdeadbeef","00-1","-+019.0","12.12.13.12",nil].each do |v|
|
611
|
-
t = Topic.create("title" => "numeric test", "content" => "whatever", "
|
611
|
+
t = Topic.create("title" => "numeric test", "content" => "whatever", "approved" => "not a number")
|
612
612
|
assert !t.valid?, "#{v} not rejected as a number"
|
613
|
-
assert t.errors.on(:
|
613
|
+
assert t.errors.on(:approved)
|
614
614
|
end
|
615
615
|
end
|
616
616
|
|
617
617
|
def test_validates_numericality_of
|
618
|
-
Topic.validates_numericality_of( :
|
619
|
-
["10", "10.0", "10.5", "-10.5", "-0.0001","0090","-090","-090.1"].each do |v|
|
620
|
-
t = Topic.create("title" => "numeric test", "content" => "whatever", "
|
618
|
+
Topic.validates_numericality_of( :approved, :allow_nil => true )
|
619
|
+
["10", "10.0", "10.5", "-10.5", "-0.0001","0090","-090","-090.1",nil,""].each do |v|
|
620
|
+
t = Topic.create("title" => "numeric test", "content" => "whatever", "approved" => v)
|
621
621
|
assert t.valid?, "#{v} not recognized as a number"
|
622
|
-
# we cannot check this as
|
623
|
-
#assert_in_delta v.to_f, t.
|
622
|
+
# we cannot check this as approved is actually an integer field
|
623
|
+
#assert_in_delta v.to_f, t.approved, 0.0000001
|
624
624
|
end
|
625
625
|
end
|
626
626
|
|
627
627
|
def test_validates_numericality_of_int_with_string
|
628
|
-
Topic.validates_numericality_of( :
|
628
|
+
Topic.validates_numericality_of( :approved, :only_integer => true )
|
629
629
|
["not a number","42 not a number","0xdeadbeef","0-1","--3","+-3","+3-1",nil].each do |v|
|
630
|
-
t = Topic.create("title" => "numeric test", "content" => "whatever", "
|
630
|
+
t = Topic.create("title" => "numeric test", "content" => "whatever", "approved" => v)
|
631
631
|
assert !t.valid?, "#{v} not rejected as integer"
|
632
|
-
assert t.errors.on(:
|
632
|
+
assert t.errors.on(:approved)
|
633
633
|
end
|
634
634
|
end
|
635
635
|
|
636
636
|
def test_validates_numericality_of_int
|
637
|
-
Topic.validates_numericality_of( :
|
638
|
-
["42", "+42", "-42", "042", "0042", "-042", 42].each do |v|
|
639
|
-
t = Topic.create("title" => "numeric test", "content" => "whatever", "
|
637
|
+
Topic.validates_numericality_of( :approved, :only_integer => true, :allow_nil => true )
|
638
|
+
["42", "+42", "-42", "042", "0042", "-042", 42, nil,""].each do |v|
|
639
|
+
t = Topic.create("title" => "numeric test", "content" => "whatever", "approved" => v)
|
640
640
|
assert t.valid?, "#{v} not recognized as integer"
|
641
|
-
assert_equal v.to_i, t.
|
641
|
+
assert_equal((v.nil? or v == "")? nil : v.to_i, t.approved)
|
642
642
|
end
|
643
643
|
end
|
644
|
-
|
644
|
+
|
645
645
|
end
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.
|
2
|
+
rubygems_version: 0.8.8
|
3
3
|
specification_version: 1
|
4
4
|
name: activerecord
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date: 2005-03-
|
6
|
+
version: 1.9.0
|
7
|
+
date: 2005-03-22
|
8
8
|
summary: Implements the ActiveRecord pattern for ORM.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -77,6 +77,7 @@ files:
|
|
77
77
|
- lib/active_record/wrappers/yaml_wrapper.rb
|
78
78
|
- test/aaa_create_tables_test.rb
|
79
79
|
- test/abstract_unit.rb
|
80
|
+
- test/active_schema_mysql.rb
|
80
81
|
- test/aggregations_test.rb
|
81
82
|
- test/all.sh
|
82
83
|
- test/association_inheritance_reload.rb
|
@@ -226,5 +227,5 @@ dependencies:
|
|
226
227
|
-
|
227
228
|
- "="
|
228
229
|
- !ruby/object:Gem::Version
|
229
|
-
version: 1.0.
|
230
|
+
version: 1.0.2
|
230
231
|
version:
|