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.
- data/CHANGELOG.md +25 -0
- data/lib/active_record/aggregations.rb +3 -0
- data/lib/active_record/associations/builder/collection_association.rb +11 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +10 -0
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +15 -5
- data/lib/active_record/autosave_association.rb +21 -15
- data/lib/active_record/base.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +9 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +3 -1
- data/lib/active_record/connection_adapters/mysql_adapter.rb +59 -44
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +7 -0
- data/lib/active_record/migration.rb +2 -2
- data/lib/active_record/persistence.rb +7 -3
- data/lib/active_record/railties/databases.rake +13 -13
- data/lib/active_record/relation/calculations.rb +20 -9
- data/lib/active_record/schema_dumper.rb +8 -4
- data/lib/active_record/version.rb +2 -2
- metadata +23 -15
data/CHANGELOG.md
CHANGED
@@ -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
|
@@ -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
|
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? &&
|
83
|
-
|
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
|
-
|
336
|
-
|
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
|
-
|
354
|
+
raise ActiveRecord::Rollback unless saved
|
355
|
+
end
|
339
356
|
|
340
|
-
|
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
|
data/lib/active_record/base.rb
CHANGED
@@ -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
|
@@ -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
|
-
|
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 =
|
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
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
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
|
-
|
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
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
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
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
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
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
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
|
-
|
386
|
+
result_set = ActiveRecord::Result.new(cols, stmt.to_a) if cols
|
387
|
+
affected_rows = stmt.affected_rows
|
374
388
|
|
375
|
-
|
376
|
-
|
377
|
-
|
389
|
+
stmt.result_metadata.free if cols
|
390
|
+
stmt.free_result
|
391
|
+
stmt.close if binds.empty?
|
378
392
|
|
379
|
-
|
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.
|
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.
|
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).
|
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).
|
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).
|
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
|
-
|
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
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|
-
|
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
|
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
|
298
|
+
key = group_columns.map { |aliaz, column|
|
289
299
|
type_cast_calculated_value(row[aliaz], column)
|
290
300
|
}
|
291
|
-
key
|
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
|
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:
|
5
|
-
prerelease:
|
4
|
+
hash: 1046071201
|
5
|
+
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
|
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-
|
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:
|
30
|
+
hash: 1046071201
|
29
31
|
segments:
|
30
32
|
- 3
|
31
33
|
- 2
|
32
|
-
-
|
33
|
-
|
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:
|
48
|
+
hash: 1046071201
|
45
49
|
segments:
|
46
50
|
- 3
|
47
51
|
- 2
|
48
|
-
-
|
49
|
-
|
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:
|
273
|
+
hash: 25
|
268
274
|
segments:
|
269
|
-
-
|
270
|
-
|
275
|
+
- 1
|
276
|
+
- 3
|
277
|
+
- 1
|
278
|
+
version: 1.3.1
|
271
279
|
requirements: []
|
272
280
|
|
273
281
|
rubyforge_project:
|