activerecord 1.15.1 → 1.15.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

data/CHANGELOG CHANGED
@@ -1,3 +1,23 @@
1
+ *1.15.2* (February 5th, 2007)
2
+
3
+ * Pass a range in :conditions to use the SQL BETWEEN operator. #6974 [dcmanges]
4
+ Student.find(:all, :conditions => { :grade => 9..12 })
5
+
6
+ * Don't create instance writer methods for class attributes. [Rick]
7
+
8
+ * When dealing with SQLite3, use the table_info pragma helper, so that the bindings can do some translation for when sqlite3 breaks incompatibly between point releases. [Jamis Buck]
9
+
10
+ * SQLServer: don't choke on strings containing 'null'. #7083 [Jakob S]
11
+
12
+ * Consistently use LOWER() for uniqueness validations (rather than mixing with UPPER()) so the database can always use a functional index on the lowercased column. #6495 [Si]
13
+
14
+ * MySQL: SET SQL_AUTO_IS_NULL=0 so 'where id is null' doesn't select the last inserted id. #6778 [Jonathan Viney, timc]
15
+
16
+ * Fixtures use the table name and connection from set_fixture_class. #7330 [Anthony Eden]
17
+
18
+ * SQLServer: quote table name in indexes query. #2928 [keithm@infused.org]
19
+
20
+
1
21
  *1.15.1* (January 17th, 2007)
2
22
 
3
23
  * Fix nodoc breaking of adapters
data/Rakefile CHANGED
@@ -151,7 +151,7 @@ spec = Gem::Specification.new do |s|
151
151
  s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
152
152
  end
153
153
 
154
- s.add_dependency('activesupport', '= 1.4.0' + PKG_BUILD)
154
+ s.add_dependency('activesupport', '= 1.4.1' + PKG_BUILD)
155
155
 
156
156
  s.files.delete "test/fixtures/fixture_database.sqlite"
157
157
  s.files.delete "test/fixtures/fixture_database_2.sqlite"
@@ -30,7 +30,7 @@ unless defined?(ActiveSupport)
30
30
  require 'active_support'
31
31
  rescue LoadError
32
32
  require 'rubygems'
33
- require_gem 'activesupport'
33
+ gem 'activesupport'
34
34
  end
35
35
  end
36
36
 
@@ -84,7 +84,7 @@ module ActiveRecord #:nodoc:
84
84
  # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement.
85
85
  # The array form is to be used when the condition input is tainted and requires sanitization. The string form can
86
86
  # be used for statements that don't involve tainted data. The hash form works much like the array form, except
87
- # only equality is possible. Examples:
87
+ # only equality and range is possible. Examples:
88
88
  #
89
89
  # class User < ActiveRecord::Base
90
90
  # def self.authenticate_unsafely(user_name, password)
@@ -120,6 +120,9 @@ module ActiveRecord #:nodoc:
120
120
  # Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 })
121
121
  # Student.find(:all, :conditions => params[:student])
122
122
  #
123
+ # A range may be used in the hash to use the SQL BETWEEN operator:
124
+ #
125
+ # Student.find(:all, :conditions => { :grade => 9..12 })
123
126
  #
124
127
  # == Overwriting default accessors
125
128
  #
@@ -262,7 +265,7 @@ module ActiveRecord #:nodoc:
262
265
  class Base
263
266
  # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then passed
264
267
  # on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+.
265
- cattr_accessor :logger
268
+ cattr_accessor :logger, :instance_writer => false
266
269
 
267
270
  include Reloadable::Deprecated
268
271
 
@@ -288,54 +291,54 @@ module ActiveRecord #:nodoc:
288
291
 
289
292
  @@subclasses = {}
290
293
 
291
- cattr_accessor :configurations
294
+ cattr_accessor :configurations, :instance_writer => false
292
295
  @@configurations = {}
293
296
 
294
297
  # Accessor for the prefix type that will be prepended to every primary key column name. The options are :table_name and
295
298
  # :table_name_with_underscore. If the first is specified, the Product class will look for "productid" instead of "id" as
296
299
  # the primary column. If the latter is specified, the Product class will look for "product_id" instead of "id". Remember
297
300
  # that this is a global setting for all Active Records.
298
- cattr_accessor :primary_key_prefix_type
301
+ cattr_accessor :primary_key_prefix_type, :instance_writer => false
299
302
  @@primary_key_prefix_type = nil
300
303
 
301
304
  # Accessor for the name of the prefix string to prepend to every table name. So if set to "basecamp_", all
302
305
  # table names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient way of creating a namespace
303
306
  # for tables in a shared database. By default, the prefix is the empty string.
304
- cattr_accessor :table_name_prefix
307
+ cattr_accessor :table_name_prefix, :instance_writer => false
305
308
  @@table_name_prefix = ""
306
309
 
307
310
  # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
308
311
  # "people_basecamp"). By default, the suffix is the empty string.
309
- cattr_accessor :table_name_suffix
312
+ cattr_accessor :table_name_suffix, :instance_writer => false
310
313
  @@table_name_suffix = ""
311
314
 
312
315
  # Indicates whether or not table names should be the pluralized versions of the corresponding class names.
313
316
  # If true, the default table name for a +Product+ class will be +products+. If false, it would just be +product+.
314
317
  # See table_name for the full rules on table/class naming. This is true, by default.
315
- cattr_accessor :pluralize_table_names
318
+ cattr_accessor :pluralize_table_names, :instance_writer => false
316
319
  @@pluralize_table_names = true
317
320
 
318
321
  # Determines whether or not to use ANSI codes to colorize the logging statements committed by the connection adapter. These colors
319
322
  # make it much easier to overview things during debugging (when used through a reader like +tail+ and on a black background), but
320
323
  # may complicate matters if you use software like syslog. This is true, by default.
321
- cattr_accessor :colorize_logging
324
+ cattr_accessor :colorize_logging, :instance_writer => false
322
325
  @@colorize_logging = true
323
326
 
324
327
  # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling dates and times from the database.
325
328
  # This is set to :local by default.
326
- cattr_accessor :default_timezone
329
+ cattr_accessor :default_timezone, :instance_writer => false
327
330
  @@default_timezone = :local
328
331
 
329
332
  # Determines whether or not to use a connection for each thread, or a single shared connection for all threads.
330
333
  # Defaults to false. Set to true if you're writing a threaded application.
331
- cattr_accessor :allow_concurrency
334
+ cattr_accessor :allow_concurrency, :instance_writer => false
332
335
  @@allow_concurrency = false
333
336
 
334
337
  # Determines whether to speed up access by generating optimized reader
335
338
  # methods to avoid expensive calls to method_missing when accessing
336
339
  # attributes by name. You might want to set this to false in development
337
340
  # mode, because the methods would be regenerated on each request.
338
- cattr_accessor :generate_read_methods
341
+ cattr_accessor :generate_read_methods, :instance_writer => false
339
342
  @@generate_read_methods = true
340
343
 
341
344
  # Specifies the format to use when dumping the database schema with Rails'
@@ -344,7 +347,7 @@ module ActiveRecord #:nodoc:
344
347
  # ActiveRecord::Schema file which can be loaded into any database that
345
348
  # supports migrations. Use :ruby if you want to have different database
346
349
  # adapters for, e.g., your development and test environments.
347
- cattr_accessor :schema_format
350
+ cattr_accessor :schema_format , :instance_writer => false
348
351
  @@schema_format = :ruby
349
352
 
350
353
  class << self # Class methods
@@ -1264,6 +1267,7 @@ module ActiveRecord #:nodoc:
1264
1267
  case argument
1265
1268
  when nil then "IS ?"
1266
1269
  when Array then "IN (?)"
1270
+ when Range then "BETWEEN ? AND ?"
1267
1271
  else "= ?"
1268
1272
  end
1269
1273
  end
@@ -1392,12 +1396,14 @@ module ActiveRecord #:nodoc:
1392
1396
  # # => "name='foo''bar' and group_id= 4"
1393
1397
  # { :status => nil, :group_id => [1,2,3] }
1394
1398
  # # => "status IS NULL and group_id IN (1,2,3)"
1399
+ # { :age => 13..18 }
1400
+ # # => "age BETWEEN 13 AND 18"
1395
1401
  def sanitize_sql_hash(attrs)
1396
1402
  conditions = attrs.map do |attr, value|
1397
1403
  "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}"
1398
1404
  end.join(' AND ')
1399
1405
 
1400
- replace_bind_variables(conditions, attrs.values)
1406
+ replace_bind_variables(conditions, expand_range_bind_variables(attrs.values))
1401
1407
  end
1402
1408
 
1403
1409
  # Accepts an array of conditions. The array has each value
@@ -1433,6 +1439,13 @@ module ActiveRecord #:nodoc:
1433
1439
  end
1434
1440
  end
1435
1441
 
1442
+ def expand_range_bind_variables(bind_vars) #:nodoc:
1443
+ bind_vars.each_with_index do |var, index|
1444
+ bind_vars[index, 1] = [var.first, var.last] if var.is_a?(Range)
1445
+ end
1446
+ bind_vars
1447
+ end
1448
+
1436
1449
  def quote_bound_value(value) #:nodoc:
1437
1450
  if value.respond_to?(:map) && !value.is_a?(String)
1438
1451
  if value.respond_to?(:empty?) && value.empty?
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
 
12
12
  # Check for activity after at least +verification_timeout+ seconds.
13
13
  # Defaults to 0 (always check.)
14
- cattr_accessor :verification_timeout
14
+ cattr_accessor :verification_timeout, :instance_writer => false
15
15
  @@verification_timeout = 0
16
16
 
17
17
  # The class -> [adapter_method, config] map
@@ -388,6 +388,10 @@ module ActiveRecord
388
388
  @connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) if @config[:sslkey]
389
389
  @connection.real_connect(*@connection_options)
390
390
  execute("SET NAMES '#{encoding}'") if encoding
391
+
392
+ # By default, MySQL 'where id is null' selects the last inserted id.
393
+ # Turn this off. http://dev.rubyonrails.org/ticket/6778
394
+ execute("SET SQL_AUTO_IS_NULL=0")
391
395
  end
392
396
 
393
397
  def select(sql, name = nil)
@@ -22,7 +22,7 @@ module ActiveRecord
22
22
 
23
23
  db.busy_timeout(config[:timeout]) unless config[:timeout].nil?
24
24
 
25
- ConnectionAdapters::SQLiteAdapter.new(db, logger)
25
+ ConnectionAdapters::SQLite3Adapter.new(db, logger)
26
26
  end
27
27
 
28
28
  # Establishes a connection to the database that's used by all Active Record objects
@@ -354,6 +354,14 @@ module ActiveRecord
354
354
  end
355
355
  end
356
356
 
357
+ class SQLite3Adapter < SQLiteAdapter # :nodoc:
358
+ def table_structure(table_name)
359
+ returning structure = @connection.table_info(table_name) do
360
+ raise ActiveRecord::StatementInvalid if structure.empty?
361
+ end
362
+ end
363
+ end
364
+
357
365
  class SQLite2Adapter < SQLiteAdapter # :nodoc:
358
366
  # SQLite 2 does not support COUNT(DISTINCT) queries:
359
367
  #
@@ -73,7 +73,7 @@ module ActiveRecord
73
73
  end
74
74
 
75
75
  def type_cast(value)
76
- return nil if value.nil? || value =~ /^\s*null\s*$/i
76
+ return nil if value.nil?
77
77
  case type
78
78
  when :datetime then cast_to_datetime(value)
79
79
  when :timestamp then cast_to_time(value)
@@ -425,7 +425,7 @@ module ActiveRecord
425
425
  def indexes(table_name, name = nil)
426
426
  ActiveRecord::Base.connection.instance_variable_get("@connection")["AutoCommit"] = false
427
427
  indexes = []
428
- execute("EXEC sp_helpindex #{table_name}", name) do |sth|
428
+ execute("EXEC sp_helpindex '#{table_name}'", name) do |sth|
429
429
  sth.each do |index|
430
430
  unique = index[1] =~ /unique/
431
431
  primary = index[1] =~ /primary key/
@@ -276,6 +276,8 @@ class Fixtures < YAML::Omap
276
276
  @class_name = class_name ||
277
277
  (ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize)
278
278
  @table_name = ActiveRecord::Base.table_name_prefix + @table_name + ActiveRecord::Base.table_name_suffix
279
+ @table_name = class_name.table_name if class_name.respond_to?(:table_name)
280
+ @connection = class_name.connection if class_name.respond_to?(:connection)
279
281
  read_fixture_files
280
282
  end
281
283
 
@@ -26,7 +26,7 @@ module ActiveRecord
26
26
  super
27
27
  base.extend ClassMethods
28
28
 
29
- base.cattr_accessor :lock_optimistically
29
+ base.cattr_accessor :lock_optimistically, :instance_writer => false
30
30
  base.lock_optimistically = true
31
31
 
32
32
  base.alias_method_chain :update, :lock
@@ -23,7 +23,7 @@ module ActiveRecord
23
23
  base.alias_method_chain :create, :timestamps
24
24
  base.alias_method_chain :update, :timestamps
25
25
 
26
- base.cattr_accessor :record_timestamps
26
+ base.cattr_accessor :record_timestamps, :instance_writer => false
27
27
  base.record_timestamps = true
28
28
  end
29
29
 
@@ -534,8 +534,8 @@ module ActiveRecord
534
534
  condition_sql = "#{record.class.table_name}.#{attr_name} #{attribute_condition(value)}"
535
535
  condition_params = [value]
536
536
  else
537
- condition_sql = "UPPER(#{record.class.table_name}.#{attr_name}) #{attribute_condition(value)}"
538
- condition_params = [value.upcase]
537
+ condition_sql = "LOWER(#{record.class.table_name}.#{attr_name}) #{attribute_condition(value)}"
538
+ condition_params = [value.downcase]
539
539
  end
540
540
  if scope = configuration[:scope]
541
541
  Array(scope).map do |scope_item|
@@ -2,7 +2,7 @@ module ActiveRecord
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
4
  MINOR = 15
5
- TINY = 1
5
+ TINY = 2
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -56,7 +56,7 @@ end
56
56
  def current_adapter?(*types)
57
57
  types.any? do |type|
58
58
  ActiveRecord::ConnectionAdapters.const_defined?(type) &&
59
- ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters.const_get(type))
59
+ ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters.const_get(type))
60
60
  end
61
61
  end
62
62
 
@@ -164,8 +164,16 @@ class BasicsTest < Test::Unit::TestCase
164
164
  topic.reload
165
165
  assert_equal("null", topic.title)
166
166
  assert_equal("null", topic.author_name)
167
- end
168
-
167
+ end
168
+
169
+ def test_save_nil_string_attributes
170
+ topic = Topic.find(1)
171
+ topic.title = nil
172
+ topic.save!
173
+ topic.reload
174
+ assert_nil topic.title
175
+ end
176
+
169
177
  def test_hashes_not_mangled
170
178
  new_topic = { :title => "New Topic" }
171
179
  new_topic_values = { :title => "AnotherTopic" }
@@ -700,6 +708,16 @@ class BasicsTest < Test::Unit::TestCase
700
708
  firm.attributes = { "name" => "Next Angle", "rating" => 5 }
701
709
  assert_equal 1, firm.rating
702
710
  end
711
+
712
+ def test_mass_assignment_protection_against_class_attribute_writers
713
+ [:logger, :configurations, :primary_key_prefix_type, :table_name_prefix, :table_name_suffix, :pluralize_table_names, :colorize_logging,
714
+ :default_timezone, :allow_concurrency, :generate_read_methods, :schema_format, :verification_timeout, :lock_optimistically, :record_timestamps].each do |method|
715
+ assert Task.respond_to?(method)
716
+ assert Task.respond_to?("#{method}=")
717
+ assert Task.new.respond_to?(method)
718
+ assert !Task.new.respond_to?("#{method}=")
719
+ end
720
+ end
703
721
 
704
722
  def test_customized_primary_key_remains_protected
705
723
  subscriber = Subscriber.new(:nick => 'webster123', :name => 'nice try')
@@ -136,6 +136,16 @@ class FinderTest < Test::Unit::TestCase
136
136
  assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :approved => true }) }
137
137
  end
138
138
 
139
+ def test_find_on_hash_conditions_with_range
140
+ assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1..2 }).map(&:id).sort
141
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :id => 2..3 }) }
142
+ end
143
+
144
+ def test_find_on_hash_conditions_with_multiple_ranges
145
+ assert_equal [1,2,3], Comment.find(:all, :conditions => { :id => 1..3, :post_id => 1..2 }).map(&:id).sort
146
+ assert_equal [1], Comment.find(:all, :conditions => { :id => 1..1, :post_id => 1..10 }).map(&:id).sort
147
+ end
148
+
139
149
  def test_find_on_multiple_hash_conditions
140
150
  assert Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false })
141
151
  assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
@@ -450,6 +460,12 @@ class FinderTest < Test::Unit::TestCase
450
460
  end
451
461
  end
452
462
 
463
+ # http://dev.rubyonrails.org/ticket/6778
464
+ def test_find_ignores_previously_inserted_record
465
+ post = Post.create!(:title => 'test', :body => 'it out')
466
+ assert_equal [], Post.find_all_by_id(nil)
467
+ end
468
+
453
469
  def test_find_by_empty_ids
454
470
  assert_equal [], Post.find([])
455
471
  end
@@ -5,6 +5,7 @@ require 'fixtures/company'
5
5
  require 'fixtures/task'
6
6
  require 'fixtures/reply'
7
7
  require 'fixtures/joke'
8
+ require 'fixtures/course'
8
9
  require 'fixtures/category'
9
10
 
10
11
  class FixturesTest < Test::Unit::TestCase
@@ -334,6 +335,16 @@ class SetTableNameFixturesTest < Test::Unit::TestCase
334
335
  end
335
336
  end
336
337
 
338
+ class CustomConnectionFixturesTest < Test::Unit::TestCase
339
+ set_fixture_class :courses => Course
340
+ fixtures :courses
341
+
342
+ def test_connection
343
+ assert_kind_of Course, courses(:ruby)
344
+ assert_equal Course.connection, courses(:ruby).connection
345
+ end
346
+ end
347
+
337
348
  class InvalidTableNameFixturesTest < Test::Unit::TestCase
338
349
  fixtures :funny_jokes
339
350
 
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: activerecord
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.15.1
7
- date: 2007-01-18 00:00:00 -06:00
6
+ version: 1.15.2
7
+ date: 2007-02-05 00:00:00 -06:00
8
8
  summary: Implements the ActiveRecord pattern for ORM.
9
9
  require_paths:
10
10
  - lib
@@ -87,7 +87,6 @@ files:
87
87
  - lib/active_record/connection_adapters/sqlserver_adapter.rb
88
88
  - lib/active_record/connection_adapters/sybase_adapter.rb
89
89
  - lib/active_record/connection_adapters/abstract/connection_specification.rb
90
- - lib/active_record/connection_adapters/abstract/connection_specification.rb.rej
91
90
  - lib/active_record/connection_adapters/abstract/database_statements.rb
92
91
  - lib/active_record/connection_adapters/abstract/quoting.rb
93
92
  - lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -354,5 +353,5 @@ dependencies:
354
353
  requirements:
355
354
  - - "="
356
355
  - !ruby/object:Gem::Version
357
- version: 1.4.0
356
+ version: 1.4.1
358
357
  version:
@@ -1,21 +0,0 @@
1
- ***************
2
- *** 90,97 ****
3
- # Clears the cache which maps classes
4
- def clear_reloadable_connections!
5
- @@active_connections.each do |name, conn|
6
- - conn.disconnect! if conn.supports_reloading?
7
- - @@active_connections.delete(name)
8
- end
9
- end
10
-
11
- --- 90,99 ----
12
- # Clears the cache which maps classes
13
- def clear_reloadable_connections!
14
- @@active_connections.each do |name, conn|
15
- + if conn.requires_reloading?
16
- + conn.disconnect!
17
- + @@active_connections.delete(name)
18
- + end
19
- end
20
- end
21
-