activerecord 3.2.6 → 3.2.7.rc1

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.

@@ -1,3 +1,28 @@
1
+ ## Rails 3.2.7 (unreleased) ##
2
+
3
+ * `:finder_sql` and `:counter_sql` options on collection associations
4
+ are deprecated. Please transition to using scopes.
5
+
6
+ *Jon Leighton*
7
+
8
+ * `:insert_sql` and `:delete_sql` options on `has_and_belongs_to_many`
9
+ associations are deprecated. Please transition to using `has_many
10
+ :through`
11
+
12
+ *Jon Leighton*
13
+
14
+ * `composed_of` has been deprecated. You'll have to write your own accessor
15
+ and mutator methods if you'd like to use value objects to represent some
16
+ portion of your models.
17
+
18
+ *Steve Klabnik*
19
+
20
+ * `update_attribute` has been deprecated. Use `update_column` if
21
+ you want to bypass mass-assignment protection, validations, callbacks,
22
+ and touching of updated_at. Otherwise please use `update_attributes`.
23
+
24
+ *Steve Klabnik*
25
+
1
26
  ## Rails 3.2.6 (Jun 12, 2012) ##
2
27
 
3
28
  * protect against the nesting of hashes changing the
@@ -161,6 +161,8 @@ module ActiveRecord
161
161
  #
162
162
  # Customer.where(:balance => Money.new(20, "USD")).all
163
163
  #
164
+ # Note: +composed_of+ has been deprecated, and will be removed (with no
165
+ # replacement) in Rails 4.
164
166
  module ClassMethods
165
167
  # Adds reader and writer methods for manipulating a value object:
166
168
  # <tt>composed_of :address</tt> adds <tt>address</tt> and <tt>address=(new_address)</tt> methods.
@@ -203,6 +205,7 @@ module ActiveRecord
203
205
  # :converter => Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
204
206
  #
205
207
  def composed_of(part_id, options = {})
208
+ ActiveSupport::Deprecation.warn("composed_of is deprecated, and will be removed in Rails 4. There is no replacement.")
206
209
  options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
207
210
 
208
211
  name = part_id.id2name
@@ -1,3 +1,5 @@
1
+ require 'active_support/deprecation'
2
+
1
3
  module ActiveRecord::Associations::Builder
2
4
  class CollectionAssociation < Association #:nodoc:
3
5
  CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
@@ -19,6 +21,7 @@ module ActiveRecord::Associations::Builder
19
21
  end
20
22
 
21
23
  def build
24
+ show_deprecation_warnings
22
25
  wrap_block_extension
23
26
  reflection = super
24
27
  CALLBACKS.each { |callback_name| define_callback(callback_name) }
@@ -29,6 +32,14 @@ module ActiveRecord::Associations::Builder
29
32
  true
30
33
  end
31
34
 
35
+ def show_deprecation_warnings
36
+ [:finder_sql, :counter_sql].each do |name|
37
+ if options.include? name
38
+ ActiveSupport::Deprecation.warn("The :#{name} association option is deprecated. Please find an alternative (such as using scopes).")
39
+ end
40
+ end
41
+ end
42
+
32
43
  private
33
44
 
34
45
  def wrap_block_extension
@@ -11,6 +11,16 @@ module ActiveRecord::Associations::Builder
11
11
  reflection
12
12
  end
13
13
 
14
+ def show_deprecation_warnings
15
+ super
16
+
17
+ [:delete_sql, :insert_sql].each do |name|
18
+ if options.include? name
19
+ ActiveSupport::Deprecation.warn("The :#{name} association option is deprecated. Please find an alternative (such as using has_many :through).")
20
+ end
21
+ end
22
+ end
23
+
14
24
  private
15
25
 
16
26
  def define_destroy_hook
@@ -36,7 +36,7 @@ module ActiveRecord
36
36
  when :destroy
37
37
  target.destroy
38
38
  when :nullify
39
- target.update_attribute(reflection.foreign_key, nil)
39
+ target.update_column(reflection.foreign_key, nil)
40
40
  end
41
41
  end
42
42
  end
@@ -64,7 +64,7 @@ module ActiveRecord
64
64
  # user.name # => "Josh"
65
65
  # user.is_admin? # => true
66
66
  def assign_attributes(new_attributes, options = {})
67
- return unless new_attributes
67
+ return if new_attributes.blank?
68
68
 
69
69
  attributes = new_attributes.stringify_keys
70
70
  multi_parameter_attributes = []
@@ -79,11 +79,8 @@ module ActiveRecord
79
79
 
80
80
  def field_changed?(attr, old, value)
81
81
  if column = column_for_attribute(attr)
82
- if column.number? && column.null && (old.nil? || old == 0) && value.blank?
83
- # For nullable numeric columns, NULL gets stored in database for blank (i.e. '') values.
84
- # Hence we don't record it as a change if the value changes from nil to ''.
85
- # If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
86
- # be typecast back to 0 (''.to_i => 0)
82
+ if column.number? && (changes_from_nil_to_empty_string?(column, old, value) ||
83
+ changes_from_zero_to_string?(old, value))
87
84
  value = nil
88
85
  else
89
86
  value = column.type_cast(value)
@@ -96,6 +93,19 @@ module ActiveRecord
96
93
  def clone_with_time_zone_conversion_attribute?(attr, old)
97
94
  old.class.name == "Time" && time_zone_aware_attributes && !self.skip_time_zone_conversion_for_attributes.include?(attr.to_sym)
98
95
  end
96
+
97
+ def changes_from_nil_to_empty_string?(column, old, value)
98
+ # For nullable numeric columns, NULL gets stored in database for blank (i.e. '') values.
99
+ # Hence we don't record it as a change if the value changes from nil to ''.
100
+ # If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
101
+ # be typecast back to 0 (''.to_i => 0)
102
+ column.null && (old.nil? || old == 0) && value.blank?
103
+ end
104
+
105
+ def changes_from_zero_to_string?(old, value)
106
+ # For columns with old 0 and value non-empty string
107
+ old == 0 && value.present? && value != '0'
108
+ end
99
109
  end
100
110
  end
101
111
  end
@@ -332,25 +332,31 @@ module ActiveRecord
332
332
 
333
333
  if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
334
334
  begin
335
- records.each do |record|
336
- next if record.destroyed?
335
+ records_to_destroy = []
336
+
337
+ records.each do |record|
338
+ next if record.destroyed?
339
+
340
+ saved = true
341
+
342
+ if autosave && record.marked_for_destruction?
343
+ records_to_destroy << record
344
+ elsif autosave != false && (@new_record_before_save || record.new_record?)
345
+ if autosave
346
+ saved = association.insert_record(record, false)
347
+ else
348
+ association.insert_record(record) unless reflection.nested?
349
+ end
350
+ elsif autosave
351
+ saved = record.save(:validate => false)
352
+ end
337
353
 
338
- saved = true
354
+ raise ActiveRecord::Rollback unless saved
355
+ end
339
356
 
340
- if autosave && record.marked_for_destruction?
357
+ records_to_destroy.each do |record|
341
358
  association.proxy.destroy(record)
342
- elsif autosave != false && (@new_record_before_save || record.new_record?)
343
- if autosave
344
- saved = association.insert_record(record, false)
345
- else
346
- association.insert_record(record) unless reflection.nested?
347
- end
348
- elsif autosave
349
- saved = record.save(:validate => false)
350
359
  end
351
-
352
- raise ActiveRecord::Rollback unless saved
353
- end
354
360
  rescue
355
361
  records.each {|x| IdentityMap.remove(x) } if IdentityMap.enabled?
356
362
  raise
@@ -697,9 +697,9 @@ module ActiveRecord #:nodoc:
697
697
  include Scoping
698
698
  extend DynamicMatchers
699
699
  include Sanitization
700
- include Integration
701
700
  include AttributeAssignment
702
701
  include ActiveModel::Conversion
702
+ include Integration
703
703
  include Validations
704
704
  extend CounterCache
705
705
  include Locking::Optimistic, Locking::Pessimistic
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  module ActiveRecord
2
4
  class Base
3
5
  class ConnectionSpecification #:nodoc:
@@ -56,7 +56,7 @@ module ActiveRecord
56
56
  end
57
57
 
58
58
  def select_all(arel, name = nil, binds = [])
59
- if @query_cache_enabled
59
+ if @query_cache_enabled && !locked?(arel)
60
60
  sql = to_sql(arel, binds)
61
61
  cache_sql(sql, binds) { super(sql, name, binds) }
62
62
  else
@@ -77,6 +77,14 @@ module ActiveRecord
77
77
 
78
78
  result.collect { |row| row.dup }
79
79
  end
80
+
81
+ def locked?(arel)
82
+ if arel.respond_to?(:locked)
83
+ arel.locked
84
+ else
85
+ false
86
+ end
87
+ end
80
88
  end
81
89
  end
82
90
  end
@@ -72,6 +72,8 @@ module ActiveRecord
72
72
  when /^mediumint/i; 3
73
73
  when /^smallint/i; 2
74
74
  when /^tinyint/i; 1
75
+ when /^enum\((.+)\)/i
76
+ $1.split(',').map{|enum| enum.strip.length - 2}.max
75
77
  else
76
78
  super
77
79
  end
@@ -325,7 +327,7 @@ module ActiveRecord
325
327
  select_all(sql).map { |table|
326
328
  table.delete('Table_type')
327
329
  sql = "SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}"
328
- exec_without_stmt(sql).first['Create Table'] + ";\n\n"
330
+ exec_query(sql).first['Create Table'] + ";\n\n"
329
331
  }.join
330
332
  end
331
333
 
@@ -214,7 +214,7 @@ module ActiveRecord
214
214
 
215
215
  def select_rows(sql, name = nil)
216
216
  @connection.query_with_result = true
217
- rows = exec_without_stmt(sql, name).rows
217
+ rows = exec_query(sql, name).rows
218
218
  @connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
219
219
  rows
220
220
  end
@@ -282,11 +282,19 @@ module ActiveRecord
282
282
  end
283
283
 
284
284
  def exec_query(sql, name = 'SQL', binds = [])
285
- log(sql, name, binds) do
286
- exec_stmt(sql, name, binds) do |cols, stmt|
287
- ActiveRecord::Result.new(cols, stmt.to_a) if cols
288
- end
285
+ # If the configuration sets prepared_statements:false, binds will
286
+ # always be empty, since the bind variables will have been already
287
+ # substituted and removed from binds by BindVisitor, so this will
288
+ # effectively disable prepared statement usage completely.
289
+ if binds.empty?
290
+ result_set, affected_rows = exec_without_stmt(sql, name)
291
+ else
292
+ result_set, affected_rows = exec_stmt(sql, name, binds)
289
293
  end
294
+
295
+ yield affected_rows if block_given?
296
+
297
+ result_set
290
298
  end
291
299
 
292
300
  def last_inserted_id(result)
@@ -298,15 +306,17 @@ module ActiveRecord
298
306
  # statement API. For those queries, we need to use this method. :'(
299
307
  log(sql, name) do
300
308
  result = @connection.query(sql)
301
- cols = []
302
- rows = []
309
+ affected_rows = @connection.affected_rows
303
310
 
304
311
  if result
305
312
  cols = result.fetch_fields.map { |field| field.name }
306
- rows = result.to_a
313
+ result_set = ActiveRecord::Result.new(cols, result.to_a)
307
314
  result.free
315
+ else
316
+ result_set = ActiveRecord::Result.new([], [])
308
317
  end
309
- ActiveRecord::Result.new(cols, rows)
318
+
319
+ [result_set, affected_rows]
310
320
  end
311
321
  end
312
322
 
@@ -324,16 +334,18 @@ module ActiveRecord
324
334
  alias :create :insert_sql
325
335
 
326
336
  def exec_delete(sql, name, binds)
327
- log(sql, name, binds) do
328
- exec_stmt(sql, name, binds) do |cols, stmt|
329
- stmt.affected_rows
330
- end
337
+ affected_rows = 0
338
+
339
+ exec_query(sql, name, binds) do |n|
340
+ affected_rows = n
331
341
  end
342
+
343
+ affected_rows
332
344
  end
333
345
  alias :exec_update :exec_delete
334
346
 
335
347
  def begin_db_transaction #:nodoc:
336
- exec_without_stmt "BEGIN"
348
+ exec_query "BEGIN"
337
349
  rescue Mysql::Error
338
350
  # Transactions aren't supported
339
351
  end
@@ -342,41 +354,44 @@ module ActiveRecord
342
354
 
343
355
  def exec_stmt(sql, name, binds)
344
356
  cache = {}
345
- if binds.empty?
346
- stmt = @connection.prepare(sql)
347
- else
348
- cache = @statements[sql] ||= {
349
- :stmt => @connection.prepare(sql)
350
- }
351
- stmt = cache[:stmt]
352
- end
357
+ log(sql, name, binds) do
358
+ if binds.empty?
359
+ stmt = @connection.prepare(sql)
360
+ else
361
+ cache = @statements[sql] ||= {
362
+ :stmt => @connection.prepare(sql)
363
+ }
364
+ stmt = cache[:stmt]
365
+ end
353
366
 
354
- begin
355
- stmt.execute(*binds.map { |col, val| type_cast(val, col) })
356
- rescue Mysql::Error => e
357
- # Older versions of MySQL leave the prepared statement in a bad
358
- # place when an error occurs. To support older mysql versions, we
359
- # need to close the statement and delete the statement from the
360
- # cache.
361
- stmt.close
362
- @statements.delete sql
363
- raise e
364
- end
367
+ begin
368
+ stmt.execute(*binds.map { |col, val| type_cast(val, col) })
369
+ rescue Mysql::Error => e
370
+ # Older versions of MySQL leave the prepared statement in a bad
371
+ # place when an error occurs. To support older mysql versions, we
372
+ # need to close the statement and delete the statement from the
373
+ # cache.
374
+ stmt.close
375
+ @statements.delete sql
376
+ raise e
377
+ end
365
378
 
366
- cols = nil
367
- if metadata = stmt.result_metadata
368
- cols = cache[:cols] ||= metadata.fetch_fields.map { |field|
369
- field.name
370
- }
371
- end
379
+ cols = nil
380
+ if metadata = stmt.result_metadata
381
+ cols = cache[:cols] ||= metadata.fetch_fields.map { |field|
382
+ field.name
383
+ }
384
+ end
372
385
 
373
- result = yield [cols, stmt]
386
+ result_set = ActiveRecord::Result.new(cols, stmt.to_a) if cols
387
+ affected_rows = stmt.affected_rows
374
388
 
375
- stmt.result_metadata.free if cols
376
- stmt.free_result
377
- stmt.close if binds.empty?
389
+ stmt.result_metadata.free if cols
390
+ stmt.free_result
391
+ stmt.close if binds.empty?
378
392
 
379
- result
393
+ [result_set, affected_rows]
394
+ end
380
395
  end
381
396
 
382
397
  def connect
@@ -1005,12 +1005,19 @@ module ActiveRecord
1005
1005
  end
1006
1006
 
1007
1007
  # Renames a table.
1008
+ # Also renames a table's primary key sequence if the sequence name matches the
1009
+ # Active Record default.
1008
1010
  #
1009
1011
  # Example:
1010
1012
  # rename_table('octopuses', 'octopi')
1011
1013
  def rename_table(name, new_name)
1012
1014
  clear_cache!
1013
1015
  execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
1016
+ pk, seq = pk_and_sequence_for(new_name)
1017
+ if seq == "#{name}_#{pk}_seq"
1018
+ new_seq = "#{new_name}_#{pk}_seq"
1019
+ execute "ALTER TABLE #{quote_table_name(seq)} RENAME TO #{quote_table_name(new_seq)}"
1020
+ end
1014
1021
  end
1015
1022
 
1016
1023
  # Adds a new column to the named table.
@@ -232,7 +232,7 @@ module ActiveRecord
232
232
  # add_column :people, :salary, :integer
233
233
  # Person.reset_column_information
234
234
  # Person.all.each do |p|
235
- # p.update_attribute :salary, SalaryCalculator.compute(p)
235
+ # p.update_column :salary, SalaryCalculator.compute(p)
236
236
  # end
237
237
  # end
238
238
  # end
@@ -252,7 +252,7 @@ module ActiveRecord
252
252
  # ...
253
253
  # say_with_time "Updating salaries..." do
254
254
  # Person.all.each do |p|
255
- # p.update_attribute :salary, SalaryCalculator.compute(p)
255
+ # p.update_column :salary, SalaryCalculator.compute(p)
256
256
  # end
257
257
  # end
258
258
  # ...
@@ -174,8 +174,12 @@ module ActiveRecord
174
174
  # * updated_at/updated_on column is updated if that column is available.
175
175
  # * Updates all the attributes that are dirty in this object.
176
176
  #
177
+ # This method has been deprecated in favor of <tt>update_column</tt> due to
178
+ # its similarity with <tt>update_attributes</tt>.
179
+ #
177
180
  def update_attribute(name, value)
178
181
  name = name.to_s
182
+ ActiveSupport::Deprecation.warn("update_attribute is deprecated and will be removed in Rails 4. If you want to skip mass-assignment protection, callbacks, and modifying updated_at, use update_column. If you do want those things, use update_attributes.")
179
183
  raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
180
184
  send("#{name}=", value)
181
185
  save(:validate => false)
@@ -239,7 +243,7 @@ module ActiveRecord
239
243
  # Saving is not subjected to validation checks. Returns +true+ if the
240
244
  # record could be saved.
241
245
  def increment!(attribute, by = 1)
242
- increment(attribute, by).update_attribute(attribute, self[attribute])
246
+ increment(attribute, by).update_column(attribute, self[attribute])
243
247
  end
244
248
 
245
249
  # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
@@ -256,7 +260,7 @@ module ActiveRecord
256
260
  # Saving is not subjected to validation checks. Returns +true+ if the
257
261
  # record could be saved.
258
262
  def decrement!(attribute, by = 1)
259
- decrement(attribute, by).update_attribute(attribute, self[attribute])
263
+ decrement(attribute, by).update_column(attribute, self[attribute])
260
264
  end
261
265
 
262
266
  # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
@@ -273,7 +277,7 @@ module ActiveRecord
273
277
  # Saving is not subjected to validation checks. Returns +true+ if the
274
278
  # record could be saved.
275
279
  def toggle!(attribute)
276
- toggle(attribute).update_attribute(attribute, self[attribute])
280
+ toggle(attribute).update_column(attribute, self[attribute])
277
281
  end
278
282
 
279
283
  # Reloads the attributes of this object from the database.
@@ -247,13 +247,13 @@ db_namespace = namespace :db do
247
247
  end
248
248
 
249
249
  # desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
250
- task :reset => :environment do
250
+ task :reset => [:environment, :load_config] do
251
251
  db_namespace["drop"].invoke
252
252
  db_namespace["setup"].invoke
253
253
  end
254
254
 
255
255
  # desc "Retrieves the charset for the current environment's database"
256
- task :charset => :environment do
256
+ task :charset => [:environment, :load_config] do
257
257
  config = ActiveRecord::Base.configurations[Rails.env || 'development']
258
258
  case config['adapter']
259
259
  when /mysql/
@@ -271,7 +271,7 @@ db_namespace = namespace :db do
271
271
  end
272
272
 
273
273
  # desc "Retrieves the collation for the current environment's database"
274
- task :collation => :environment do
274
+ task :collation => [:environment, :load_config] do
275
275
  config = ActiveRecord::Base.configurations[Rails.env || 'development']
276
276
  case config['adapter']
277
277
  when /mysql/
@@ -283,12 +283,12 @@ db_namespace = namespace :db do
283
283
  end
284
284
 
285
285
  desc 'Retrieves the current schema version number'
286
- task :version => :environment do
286
+ task :version => [:environment, :load_config] do
287
287
  puts "Current version: #{ActiveRecord::Migrator.current_version}"
288
288
  end
289
289
 
290
290
  # desc "Raises an error if there are pending migrations"
291
- task :abort_if_pending_migrations => :environment do
291
+ task :abort_if_pending_migrations => [:environment, :load_config] do
292
292
  pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
293
293
 
294
294
  if pending_migrations.any?
@@ -311,7 +311,7 @@ db_namespace = namespace :db do
311
311
 
312
312
  namespace :fixtures do
313
313
  desc "Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
314
- task :load => :environment do
314
+ task :load => [:environment, :load_config] do
315
315
  require 'active_record/fixtures'
316
316
 
317
317
  ActiveRecord::Base.establish_connection(Rails.env)
@@ -324,7 +324,7 @@ db_namespace = namespace :db do
324
324
  end
325
325
 
326
326
  # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
327
- task :identify => :environment do
327
+ task :identify => [:environment, :load_config] do
328
328
  require 'active_record/fixtures'
329
329
 
330
330
  label, id = ENV['LABEL'], ENV['ID']
@@ -360,7 +360,7 @@ db_namespace = namespace :db do
360
360
  end
361
361
 
362
362
  desc 'Load a schema.rb file into the database'
363
- task :load => :environment do
363
+ task :load => [:environment, :load_config] do
364
364
  file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
365
365
  if File.exists?(file)
366
366
  load(file)
@@ -376,7 +376,7 @@ db_namespace = namespace :db do
376
376
 
377
377
  namespace :structure do
378
378
  desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql'
379
- task :dump => :environment do
379
+ task :dump => [:environment, :load_config] do
380
380
  abcs = ActiveRecord::Base.configurations
381
381
  filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
382
382
  case abcs[Rails.env]['adapter']
@@ -459,7 +459,7 @@ db_namespace = namespace :db do
459
459
  db_namespace["test:load_schema"].invoke
460
460
  when :sql
461
461
  db_namespace["test:load_structure"].invoke
462
- end
462
+ end
463
463
  end
464
464
 
465
465
  # desc "Recreate the test database from an existent structure.sql file"
@@ -486,7 +486,7 @@ db_namespace = namespace :db do
486
486
  task :clone_structure => [ "db:structure:dump", "db:test:load_structure" ]
487
487
 
488
488
  # desc "Empty the test database"
489
- task :purge => :environment do
489
+ task :purge => [:environment, :load_config] do
490
490
  abcs = ActiveRecord::Base.configurations
491
491
  case abcs['test']['adapter']
492
492
  when /mysql/
@@ -528,7 +528,7 @@ db_namespace = namespace :db do
528
528
 
529
529
  namespace :sessions do
530
530
  # desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
531
- task :create => :environment do
531
+ task :create => [:environment, :load_config] do
532
532
  raise 'Task unavailable to this database (no migration support)' unless ActiveRecord::Base.connection.supports_migrations?
533
533
  Rails.application.load_generators
534
534
  require 'rails/generators/rails/session_migration/session_migration_generator'
@@ -536,7 +536,7 @@ db_namespace = namespace :db do
536
536
  end
537
537
 
538
538
  # desc "Clear the sessions table"
539
- task :clear => :environment do
539
+ task :clear => [:environment, :load_config] do
540
540
  ActiveRecord::Base.connection.execute "DELETE FROM #{session_table_name}"
541
541
  end
542
542
  end
@@ -244,10 +244,16 @@ module ActiveRecord
244
244
  end
245
245
 
246
246
  def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
247
- group_attr = @group_values
248
- association = @klass.reflect_on_association(group_attr.first.to_sym)
249
- associated = group_attr.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
250
- group_fields = Array(associated ? association.foreign_key : group_attr)
247
+ group_attrs = @group_values
248
+
249
+ if group_attrs.first.respond_to?(:to_sym)
250
+ association = @klass.reflect_on_association(group_attrs.first.to_sym)
251
+ associated = group_attrs.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
252
+ group_fields = Array(associated ? association.foreign_key : group_attrs)
253
+ else
254
+ group_fields = group_attrs
255
+ end
256
+
251
257
  group_aliases = group_fields.map { |field| column_alias_for(field) }
252
258
  group_columns = group_aliases.zip(group_fields).map { |aliaz,field|
253
259
  [aliaz, column_for(field)]
@@ -270,10 +276,14 @@ module ActiveRecord
270
276
  select_values += @select_values unless @having_values.empty?
271
277
 
272
278
  select_values.concat group_fields.zip(group_aliases).map { |field,aliaz|
273
- "#{field} AS #{aliaz}"
279
+ if field.respond_to?(:as)
280
+ field.as(aliaz)
281
+ else
282
+ "#{field} AS #{aliaz}"
283
+ end
274
284
  }
275
285
 
276
- relation = except(:group).group(group.join(','))
286
+ relation = except(:group).group(group)
277
287
  relation.select_values = select_values
278
288
 
279
289
  calculated_data = @klass.connection.select_all(relation)
@@ -285,10 +295,10 @@ module ActiveRecord
285
295
  end
286
296
 
287
297
  ActiveSupport::OrderedHash[calculated_data.map do |row|
288
- key = group_columns.map { |aliaz, column|
298
+ key = group_columns.map { |aliaz, column|
289
299
  type_cast_calculated_value(row[aliaz], column)
290
300
  }
291
- key = key.first if key.size == 1
301
+ key = key.first if key.size == 1
292
302
  key = key_records[key] if associated
293
303
  [key, type_cast_calculated_value(row[aggregate_alias], column_for(column_name), operation)]
294
304
  end]
@@ -303,6 +313,7 @@ module ActiveRecord
303
313
  # column_alias_for("count(*)") # => "count_all"
304
314
  # column_alias_for("count", "id") # => "count_id"
305
315
  def column_alias_for(*keys)
316
+ keys.map! {|k| k.respond_to?(:to_sql) ? k.to_sql : k}
306
317
  table_name = keys.join(' ')
307
318
  table_name.downcase!
308
319
  table_name.gsub!(/\*/, 'all')
@@ -314,7 +325,7 @@ module ActiveRecord
314
325
  end
315
326
 
316
327
  def column_for(field)
317
- field_name = field.to_s.split('.').last
328
+ field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split('.').last
318
329
  @klass.columns.detect { |c| c.name.to_s == field_name }
319
330
  end
320
331
 
@@ -70,8 +70,8 @@ HEADER
70
70
  @connection.tables.sort.each do |tbl|
71
71
  next if ['schema_migrations', ignore_tables].flatten.any? do |ignored|
72
72
  case ignored
73
- when String; tbl == ignored
74
- when Regexp; tbl =~ ignored
73
+ when String; remove_prefix_and_suffix(tbl) == ignored
74
+ when Regexp; remove_prefix_and_suffix(tbl) =~ ignored
75
75
  else
76
76
  raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
77
77
  end
@@ -92,7 +92,7 @@ HEADER
92
92
  pk = @connection.primary_key(table)
93
93
  end
94
94
 
95
- tbl.print " create_table #{table.inspect}"
95
+ tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
96
96
  if columns.detect { |c| c.name == pk }
97
97
  if pk != 'id'
98
98
  tbl.print %Q(, :primary_key => "#{pk}")
@@ -181,7 +181,7 @@ HEADER
181
181
  if (indexes = @connection.indexes(table)).any?
182
182
  add_index_statements = indexes.map do |index|
183
183
  statement_parts = [
184
- ('add_index ' + index.table.inspect),
184
+ ('add_index ' + remove_prefix_and_suffix(index.table).inspect),
185
185
  index.columns.inspect,
186
186
  (':name => ' + index.name.inspect),
187
187
  ]
@@ -200,5 +200,9 @@ HEADER
200
200
  stream.puts
201
201
  end
202
202
  end
203
+
204
+ def remove_prefix_and_suffix(table)
205
+ table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
206
+ end
203
207
  end
204
208
  end
@@ -2,8 +2,8 @@ module ActiveRecord
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 3
4
4
  MINOR = 2
5
- TINY = 6
6
- PRE = nil
5
+ TINY = 7
6
+ PRE = "rc1"
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
9
  end
metadata CHANGED
@@ -1,13 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
5
- prerelease:
4
+ hash: 1046071201
5
+ prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
- - 6
10
- version: 3.2.6
9
+ - 7
10
+ - rc
11
+ - 1
12
+ version: 3.2.7.rc1
11
13
  platform: ruby
12
14
  authors:
13
15
  - David Heinemeier Hansson
@@ -15,7 +17,7 @@ autorequire:
15
17
  bindir: bin
16
18
  cert_chain: []
17
19
 
18
- date: 2012-06-12 00:00:00 Z
20
+ date: 2012-07-23 00:00:00 Z
19
21
  dependencies:
20
22
  - !ruby/object:Gem::Dependency
21
23
  name: activesupport
@@ -25,12 +27,14 @@ dependencies:
25
27
  requirements:
26
28
  - - "="
27
29
  - !ruby/object:Gem::Version
28
- hash: 3
30
+ hash: 1046071201
29
31
  segments:
30
32
  - 3
31
33
  - 2
32
- - 6
33
- version: 3.2.6
34
+ - 7
35
+ - rc
36
+ - 1
37
+ version: 3.2.7.rc1
34
38
  type: :runtime
35
39
  version_requirements: *id001
36
40
  - !ruby/object:Gem::Dependency
@@ -41,12 +45,14 @@ dependencies:
41
45
  requirements:
42
46
  - - "="
43
47
  - !ruby/object:Gem::Version
44
- hash: 3
48
+ hash: 1046071201
45
49
  segments:
46
50
  - 3
47
51
  - 2
48
- - 6
49
- version: 3.2.6
52
+ - 7
53
+ - rc
54
+ - 1
55
+ version: 3.2.7.rc1
50
56
  type: :runtime
51
57
  version_requirements: *id002
52
58
  - !ruby/object:Gem::Dependency
@@ -262,12 +268,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
262
268
  required_rubygems_version: !ruby/object:Gem::Requirement
263
269
  none: false
264
270
  requirements:
265
- - - ">="
271
+ - - ">"
266
272
  - !ruby/object:Gem::Version
267
- hash: 3
273
+ hash: 25
268
274
  segments:
269
- - 0
270
- version: "0"
275
+ - 1
276
+ - 3
277
+ - 1
278
+ version: 1.3.1
271
279
  requirements: []
272
280
 
273
281
  rubyforge_project: