activerecord 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +776 -1330
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +14 -13
- data/lib/active_record/associations/association.rb +2 -2
- data/lib/active_record/associations/association_scope.rb +83 -43
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +15 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -6
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +66 -29
- data/lib/active_record/associations/collection_proxy.rb +22 -26
- data/lib/active_record/associations/has_many_association.rb +65 -18
- data/lib/active_record/associations/has_many_through_association.rb +55 -27
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +19 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +20 -12
- data/lib/active_record/associations/preloader/association.rb +34 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/preloader.rb +49 -59
- data/lib/active_record/associations/singular_association.rb +25 -4
- data/lib/active_record/associations/through_association.rb +23 -14
- data/lib/active_record/associations.rb +171 -42
- data/lib/active_record/attribute.rb +149 -0
- data/lib/active_record/attribute_assignment.rb +18 -10
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +98 -44
- data/lib/active_record/attribute_methods/primary_key.rb +14 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +37 -147
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +34 -28
- data/lib/active_record/attribute_methods/write.rb +14 -21
- data/lib/active_record/attribute_methods.rb +67 -94
- data/lib/active_record/attribute_set/builder.rb +86 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attributes.rb +139 -0
- data/lib/active_record/autosave_association.rb +45 -38
- data/lib/active_record/base.rb +10 -20
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +78 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +38 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -55
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +126 -54
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +198 -64
- data/lib/active_record/connection_adapters/abstract/transaction.rb +126 -114
- data/lib/active_record/connection_adapters/abstract_adapter.rb +154 -55
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +240 -135
- data/lib/active_record/connection_adapters/column.rb +28 -239
- data/lib/active_record/connection_adapters/connection_specification.rb +16 -25
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -22
- data/lib/active_record/connection_adapters/mysql_adapter.rb +65 -149
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -27
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -374
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +55 -135
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +127 -38
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +220 -466
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -61
- data/lib/active_record/connection_handling.rb +3 -3
- data/lib/active_record/core.rb +143 -32
- data/lib/active_record/counter_cache.rb +60 -7
- data/lib/active_record/enum.rb +10 -11
- data/lib/active_record/errors.rb +49 -27
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +56 -70
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +35 -17
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +52 -49
- data/lib/active_record/model_schema.rb +49 -57
- data/lib/active_record/nested_attributes.rb +7 -7
- data/lib/active_record/null_relation.rb +19 -5
- data/lib/active_record/persistence.rb +50 -31
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +14 -11
- data/lib/active_record/railties/databases.rake +56 -54
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +286 -102
- data/lib/active_record/relation/batches.rb +0 -1
- data/lib/active_record/relation/calculations.rb +39 -31
- data/lib/active_record/relation/delegation.rb +2 -2
- data/lib/active_record/relation/finder_methods.rb +80 -36
- data/lib/active_record/relation/merger.rb +25 -30
- data/lib/active_record/relation/predicate_builder/array_handler.rb +31 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +11 -10
- data/lib/active_record/relation/query_methods.rb +141 -55
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/relation.rb +69 -30
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +58 -26
- data/lib/active_record/schema_migration.rb +11 -0
- data/lib/active_record/scoping/default.rb +8 -7
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +19 -10
- data/lib/active_record/tasks/database_tasks.rb +73 -7
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +11 -9
- data/lib/active_record/transactions.rb +37 -21
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +30 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
- data/lib/active_record/type/integer.rb +55 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +56 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +6 -4
- data/lib/active_record/validations/uniqueness.rb +11 -17
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record.rb +3 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +4 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +6 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +65 -10
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -23,7 +23,7 @@ module ActiveRecord
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def size
|
26
|
-
|
26
|
+
calculate :size, nil
|
27
27
|
end
|
28
28
|
|
29
29
|
def empty?
|
@@ -43,18 +43,32 @@ module ActiveRecord
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def count(*)
|
46
|
-
|
46
|
+
calculate :count, nil
|
47
47
|
end
|
48
48
|
|
49
49
|
def sum(*)
|
50
|
-
|
50
|
+
calculate :sum, nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def average(*)
|
54
|
+
calculate :average, nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def minimum(*)
|
58
|
+
calculate :minimum, nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def maximum(*)
|
62
|
+
calculate :maximum, nil
|
51
63
|
end
|
52
64
|
|
53
65
|
def calculate(operation, _column_name, _options = {})
|
54
66
|
# TODO: Remove _options argument as soon we remove support to
|
55
67
|
# activerecord-deprecated_finders.
|
56
|
-
if
|
57
|
-
0
|
68
|
+
if [:count, :sum, :size].include? operation
|
69
|
+
group_values.any? ? Hash.new : 0
|
70
|
+
elsif [:average, :minimum, :maximum].include?(operation) && group_values.any?
|
71
|
+
Hash.new
|
58
72
|
else
|
59
73
|
nil
|
60
74
|
end
|
@@ -36,8 +36,25 @@ module ActiveRecord
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
# Creates an object (or multiple objects) and saves it to the database,
|
40
|
+
# if validations pass. Raises a RecordInvalid error if validations fail,
|
41
|
+
# unlike Base#create.
|
42
|
+
#
|
43
|
+
# The +attributes+ parameter can be either a Hash or an Array of Hashes.
|
44
|
+
# These describe which attributes to be created on the object, or
|
45
|
+
# multiple objects when given an Array of Hashes.
|
46
|
+
def create!(attributes = nil, &block)
|
47
|
+
if attributes.is_a?(Array)
|
48
|
+
attributes.collect { |attr| create!(attr, &block) }
|
49
|
+
else
|
50
|
+
object = new(attributes, &block)
|
51
|
+
object.save!
|
52
|
+
object
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
39
56
|
# Given an attributes hash, +instantiate+ returns a new instance of
|
40
|
-
# the appropriate class.
|
57
|
+
# the appropriate class. Accepts only keys as strings.
|
41
58
|
#
|
42
59
|
# For example, +Post.all+ may return Comments, Messages, and Emails
|
43
60
|
# by storing the record's subclass in a +type+ attribute. By calling
|
@@ -46,10 +63,10 @@ module ActiveRecord
|
|
46
63
|
#
|
47
64
|
# See +ActiveRecord::Inheritance#discriminate_class_for_record+ to see
|
48
65
|
# how this "single-table" inheritance mapping is implemented.
|
49
|
-
def instantiate(
|
50
|
-
klass = discriminate_class_for_record(
|
51
|
-
|
52
|
-
klass.allocate.init_with('attributes' =>
|
66
|
+
def instantiate(attributes, column_types = {})
|
67
|
+
klass = discriminate_class_for_record(attributes)
|
68
|
+
attributes = klass.attributes_builder.build_from_database(attributes, column_types)
|
69
|
+
klass.allocate.init_with('attributes' => attributes, 'new_record' => false)
|
53
70
|
end
|
54
71
|
|
55
72
|
private
|
@@ -122,7 +139,7 @@ module ActiveRecord
|
|
122
139
|
# Attributes marked as readonly are silently ignored if the record is
|
123
140
|
# being updated.
|
124
141
|
def save!(*)
|
125
|
-
create_or_update || raise(RecordNotSaved)
|
142
|
+
create_or_update || raise(RecordNotSaved.new(nil, self))
|
126
143
|
end
|
127
144
|
|
128
145
|
# Deletes the record in the database and freezes this instance to
|
@@ -149,7 +166,7 @@ module ActiveRecord
|
|
149
166
|
# and <tt>destroy</tt> returns +false+. See
|
150
167
|
# ActiveRecord::Callbacks for further details.
|
151
168
|
def destroy
|
152
|
-
raise ReadOnlyRecord if readonly?
|
169
|
+
raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
|
153
170
|
destroy_associations
|
154
171
|
destroy_row if persisted?
|
155
172
|
@destroyed = true
|
@@ -164,7 +181,7 @@ module ActiveRecord
|
|
164
181
|
# and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
|
165
182
|
# ActiveRecord::Callbacks for further details.
|
166
183
|
def destroy!
|
167
|
-
destroy || raise(ActiveRecord::RecordNotDestroyed)
|
184
|
+
destroy || raise(ActiveRecord::RecordNotDestroyed, self)
|
168
185
|
end
|
169
186
|
|
170
187
|
# Returns an instance of the specified +klass+ with the attributes of the
|
@@ -180,7 +197,6 @@ module ActiveRecord
|
|
180
197
|
def becomes(klass)
|
181
198
|
became = klass.new
|
182
199
|
became.instance_variable_set("@attributes", @attributes)
|
183
|
-
became.instance_variable_set("@attributes_cache", @attributes_cache)
|
184
200
|
became.instance_variable_set("@changed_attributes", @changed_attributes) if defined?(@changed_attributes)
|
185
201
|
became.instance_variable_set("@new_record", new_record?)
|
186
202
|
became.instance_variable_set("@destroyed", destroyed?)
|
@@ -214,6 +230,8 @@ module ActiveRecord
|
|
214
230
|
#
|
215
231
|
# This method raises an +ActiveRecord::ActiveRecordError+ if the
|
216
232
|
# attribute is marked as readonly.
|
233
|
+
#
|
234
|
+
# See also +update_column+.
|
217
235
|
def update_attribute(name, value)
|
218
236
|
name = name.to_s
|
219
237
|
verify_readonly_attribute(name)
|
@@ -269,7 +287,8 @@ module ActiveRecord
|
|
269
287
|
# This method raises an +ActiveRecord::ActiveRecordError+ when called on new
|
270
288
|
# objects, or when at least one of the attributes is marked as readonly.
|
271
289
|
def update_columns(attributes)
|
272
|
-
raise ActiveRecordError, "cannot update
|
290
|
+
raise ActiveRecordError, "cannot update a new record" if new_record?
|
291
|
+
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
273
292
|
|
274
293
|
attributes.each_key do |key|
|
275
294
|
verify_readonly_attribute(key.to_s)
|
@@ -394,24 +413,24 @@ module ActiveRecord
|
|
394
413
|
self.class.unscoped { self.class.find(id) }
|
395
414
|
end
|
396
415
|
|
397
|
-
@attributes
|
398
|
-
|
399
|
-
@column_types = self.class.column_types
|
400
|
-
@column_types_override = fresh_object.instance_variable_get('@column_types_override')
|
401
|
-
@attributes_cache = {}
|
416
|
+
@attributes = fresh_object.instance_variable_get('@attributes')
|
417
|
+
@new_record = false
|
402
418
|
self
|
403
419
|
end
|
404
420
|
|
405
421
|
# Saves the record with the updated_at/on attributes set to the current time.
|
406
|
-
# Please note that no validation is performed and only the +after_touch
|
407
|
-
#
|
408
|
-
#
|
409
|
-
# updated_at/on
|
422
|
+
# Please note that no validation is performed and only the +after_touch+,
|
423
|
+
# +after_commit+ and +after_rollback+ callbacks are executed.
|
424
|
+
#
|
425
|
+
# If attribute names are passed, they are updated along with updated_at/on
|
426
|
+
# attributes.
|
410
427
|
#
|
411
|
-
# product.touch
|
412
|
-
# product.touch(:designed_at)
|
428
|
+
# product.touch # updates updated_at/on
|
429
|
+
# product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
|
430
|
+
# product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
|
413
431
|
#
|
414
|
-
# If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
|
432
|
+
# If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
|
433
|
+
# associated object.
|
415
434
|
#
|
416
435
|
# class Brake < ActiveRecord::Base
|
417
436
|
# belongs_to :car, touch: true
|
@@ -430,11 +449,11 @@ module ActiveRecord
|
|
430
449
|
# ball = Ball.new
|
431
450
|
# ball.touch(:updated_at) # => raises ActiveRecordError
|
432
451
|
#
|
433
|
-
def touch(
|
452
|
+
def touch(*names)
|
434
453
|
raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
|
435
454
|
|
436
455
|
attributes = timestamp_attributes_for_update_in_model
|
437
|
-
attributes
|
456
|
+
attributes.concat(names)
|
438
457
|
|
439
458
|
unless attributes.empty?
|
440
459
|
current_time = current_time_from_proper_timezone
|
@@ -447,7 +466,7 @@ module ActiveRecord
|
|
447
466
|
|
448
467
|
changes[self.class.locking_column] = increment_lock if locking_enabled?
|
449
468
|
|
450
|
-
|
469
|
+
clear_attribute_changes(changes.keys)
|
451
470
|
primary_key = self.class.primary_key
|
452
471
|
self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
|
453
472
|
else
|
@@ -468,7 +487,7 @@ module ActiveRecord
|
|
468
487
|
def relation_for_destroy
|
469
488
|
pk = self.class.primary_key
|
470
489
|
column = self.class.columns_hash[pk]
|
471
|
-
substitute = self.class.connection.substitute_at(column
|
490
|
+
substitute = self.class.connection.substitute_at(column)
|
472
491
|
|
473
492
|
relation = self.class.unscoped.where(
|
474
493
|
self.class.arel_table[pk].eq(substitute))
|
@@ -478,25 +497,25 @@ module ActiveRecord
|
|
478
497
|
end
|
479
498
|
|
480
499
|
def create_or_update
|
481
|
-
raise ReadOnlyRecord if readonly?
|
482
|
-
result = new_record? ?
|
500
|
+
raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
|
501
|
+
result = new_record? ? _create_record : _update_record
|
483
502
|
result != false
|
484
503
|
end
|
485
504
|
|
486
505
|
# Updates the associated record with values matching those of the instance attributes.
|
487
506
|
# Returns the number of affected rows.
|
488
|
-
def
|
507
|
+
def _update_record(attribute_names = self.attribute_names)
|
489
508
|
attributes_values = arel_attributes_with_values_for_update(attribute_names)
|
490
509
|
if attributes_values.empty?
|
491
510
|
0
|
492
511
|
else
|
493
|
-
self.class.unscoped.
|
512
|
+
self.class.unscoped._update_record attributes_values, id, id_was
|
494
513
|
end
|
495
514
|
end
|
496
515
|
|
497
516
|
# Creates a record with values matching those of the instance attributes
|
498
517
|
# and returns its id.
|
499
|
-
def
|
518
|
+
def _create_record(attribute_names = self.attribute_names)
|
500
519
|
attributes_values = arel_attributes_with_values_for_create(attribute_names)
|
501
520
|
|
502
521
|
new_id = self.class.unscoped.insert attributes_values
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module ActiveRecord
|
3
2
|
# = Active Record Query Cache
|
4
3
|
class QueryCache
|
@@ -29,9 +28,10 @@ module ActiveRecord
|
|
29
28
|
end
|
30
29
|
|
31
30
|
def call(env)
|
32
|
-
|
31
|
+
connection = ActiveRecord::Base.connection
|
32
|
+
enabled = connection.query_cache_enabled
|
33
33
|
connection_id = ActiveRecord::Base.connection_id
|
34
|
-
|
34
|
+
connection.enable_query_cache!
|
35
35
|
|
36
36
|
response = @app.call(env)
|
37
37
|
response[2] = Rack::BodyProxy.new(response[2]) do
|
@@ -37,15 +37,18 @@ module ActiveRecord
|
|
37
37
|
# Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
|
38
38
|
def find_by_sql(sql, binds = [])
|
39
39
|
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds)
|
40
|
-
column_types =
|
40
|
+
column_types = result_set.column_types.dup
|
41
|
+
columns_hash.each_key { |k| column_types.delete k }
|
42
|
+
message_bus = ActiveSupport::Notifications.instrumenter
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
44
|
+
payload = {
|
45
|
+
record_count: result_set.length,
|
46
|
+
class_name: name
|
47
|
+
}
|
47
48
|
|
48
|
-
|
49
|
+
message_bus.instrument('instantiation.active_record', payload) do
|
50
|
+
result_set.map { |record| instantiate(record, column_types) }
|
51
|
+
end
|
49
52
|
end
|
50
53
|
|
51
54
|
# Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
|
@@ -36,8 +36,6 @@ module ActiveRecord
|
|
36
36
|
config.eager_load_namespaces << ActiveRecord
|
37
37
|
|
38
38
|
rake_tasks do
|
39
|
-
require "active_record/base"
|
40
|
-
|
41
39
|
namespace :db do
|
42
40
|
task :load_config do
|
43
41
|
ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration
|
@@ -116,17 +114,22 @@ module ActiveRecord
|
|
116
114
|
# and then establishes the connection.
|
117
115
|
initializer "active_record.initialize_database" do |app|
|
118
116
|
ActiveSupport.on_load(:active_record) do
|
117
|
+
self.configurations = Rails.application.config.database_configuration
|
119
118
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
end
|
126
|
-
end
|
119
|
+
begin
|
120
|
+
establish_connection
|
121
|
+
rescue ActiveRecord::NoDatabaseError
|
122
|
+
warn <<-end_warning
|
123
|
+
Oops - You have a database configured, but it doesn't exist yet!
|
127
124
|
|
128
|
-
|
129
|
-
|
125
|
+
Here's how to get started:
|
126
|
+
|
127
|
+
1. Configure your database in config/database.yml.
|
128
|
+
2. Run `bin/rake db:create` to create the database.
|
129
|
+
3. Run `bin/rake db:setup` to load your database schema.
|
130
|
+
end_warning
|
131
|
+
raise
|
132
|
+
end
|
130
133
|
end
|
131
134
|
end
|
132
135
|
|
@@ -28,12 +28,20 @@ db_namespace = namespace :db do
|
|
28
28
|
ActiveRecord::Tasks::DatabaseTasks.drop_current
|
29
29
|
end
|
30
30
|
|
31
|
+
namespace :purge do
|
32
|
+
task :all => :load_config do
|
33
|
+
ActiveRecord::Tasks::DatabaseTasks.purge_all
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# desc "Empty the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV it defaults to purging the development and test databases."
|
38
|
+
task :purge => [:load_config] do
|
39
|
+
ActiveRecord::Tasks::DatabaseTasks.purge_current
|
40
|
+
end
|
41
|
+
|
31
42
|
desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
|
32
43
|
task :migrate => [:environment, :load_config] do
|
33
|
-
ActiveRecord::
|
34
|
-
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
|
35
|
-
ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
|
36
|
-
end
|
44
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate
|
37
45
|
db_namespace['_dump'].invoke if ActiveRecord::Base.dump_schema_after_migration
|
38
46
|
end
|
39
47
|
|
@@ -82,22 +90,21 @@ db_namespace = namespace :db do
|
|
82
90
|
|
83
91
|
desc 'Display status of migrations'
|
84
92
|
task :status => [:environment, :load_config] do
|
85
|
-
unless ActiveRecord::
|
86
|
-
|
87
|
-
next # means "return" for rake task
|
93
|
+
unless ActiveRecord::SchemaMigration.table_exists?
|
94
|
+
abort 'Schema migrations table does not exist yet.'
|
88
95
|
end
|
89
|
-
db_list = ActiveRecord::
|
90
|
-
|
91
|
-
file_list =
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
96
|
+
db_list = ActiveRecord::SchemaMigration.normalized_versions
|
97
|
+
|
98
|
+
file_list =
|
99
|
+
ActiveRecord::Migrator.migrations_paths.flat_map do |path|
|
100
|
+
# match "20091231235959_some_name.rb" and "001_some_name.rb" pattern
|
101
|
+
Dir.foreach(path).grep(/^(\d{3,})_(.+)\.rb$/) do
|
102
|
+
version = ActiveRecord::SchemaMigration.normalize_migration_number($1)
|
103
|
+
status = db_list.delete(version) ? 'up' : 'down'
|
104
|
+
[status, version, $2.humanize]
|
105
|
+
end
|
98
106
|
end
|
99
|
-
|
100
|
-
end
|
107
|
+
|
101
108
|
db_list.map! do |version|
|
102
109
|
['up', version, '********** NO FILE **********']
|
103
110
|
end
|
@@ -105,8 +112,8 @@ db_namespace = namespace :db do
|
|
105
112
|
puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
|
106
113
|
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
107
114
|
puts "-" * 50
|
108
|
-
(db_list + file_list).sort_by {|
|
109
|
-
puts "#{
|
115
|
+
(db_list + file_list).sort_by { |_, version, _| version }.each do |status, version, name|
|
116
|
+
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
|
110
117
|
end
|
111
118
|
puts
|
112
119
|
end
|
@@ -178,17 +185,22 @@ db_namespace = namespace :db do
|
|
178
185
|
task :load => [:environment, :load_config] do
|
179
186
|
require 'active_record/fixtures'
|
180
187
|
|
181
|
-
base_dir =
|
182
|
-
File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
|
183
|
-
else
|
184
|
-
ActiveRecord::Tasks::DatabaseTasks.fixtures_path
|
185
|
-
end
|
188
|
+
base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
|
186
189
|
|
187
|
-
fixtures_dir =
|
190
|
+
fixtures_dir = if ENV['FIXTURES_DIR']
|
191
|
+
File.join base_dir, ENV['FIXTURES_DIR']
|
192
|
+
else
|
193
|
+
base_dir
|
194
|
+
end
|
188
195
|
|
189
|
-
|
190
|
-
|
191
|
-
|
196
|
+
fixture_files = if ENV['FIXTURES']
|
197
|
+
ENV['FIXTURES'].split(',')
|
198
|
+
else
|
199
|
+
# The use of String#[] here is to support namespaced fixtures
|
200
|
+
Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }
|
201
|
+
end
|
202
|
+
|
203
|
+
ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files)
|
192
204
|
end
|
193
205
|
|
194
206
|
# desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
|
@@ -200,16 +212,11 @@ db_namespace = namespace :db do
|
|
200
212
|
|
201
213
|
puts %Q(The fixture ID for "#{label}" is #{ActiveRecord::FixtureSet.identify(label)}.) if label
|
202
214
|
|
203
|
-
base_dir =
|
204
|
-
File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
|
205
|
-
else
|
206
|
-
ActiveRecord::Tasks::DatabaseTasks.fixtures_path
|
207
|
-
end
|
208
|
-
|
215
|
+
base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
|
209
216
|
|
210
217
|
Dir["#{base_dir}/**/*.yml"].each do |file|
|
211
218
|
if data = YAML::load(ERB.new(IO.read(file)).result)
|
212
|
-
data.
|
219
|
+
data.each_key do |key|
|
213
220
|
key_id = ActiveRecord::FixtureSet.identify(key)
|
214
221
|
|
215
222
|
if key == label || key_id == id.to_i
|
@@ -234,7 +241,7 @@ db_namespace = namespace :db do
|
|
234
241
|
|
235
242
|
desc 'Load a schema.rb file into the database'
|
236
243
|
task :load => [:environment, :load_config] do
|
237
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
244
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA'])
|
238
245
|
end
|
239
246
|
|
240
247
|
task :load_if_ruby => ['db:create', :environment] do
|
@@ -268,7 +275,8 @@ db_namespace = namespace :db do
|
|
268
275
|
current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
|
269
276
|
ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
|
270
277
|
|
271
|
-
if ActiveRecord::Base.connection.supports_migrations?
|
278
|
+
if ActiveRecord::Base.connection.supports_migrations? &&
|
279
|
+
ActiveRecord::SchemaMigration.table_exists?
|
272
280
|
File.open(filename, "a") do |f|
|
273
281
|
f.puts ActiveRecord::Base.connection.dump_schema_information
|
274
282
|
f.print "\n"
|
@@ -277,9 +285,9 @@ db_namespace = namespace :db do
|
|
277
285
|
db_namespace['structure:dump'].reenable
|
278
286
|
end
|
279
287
|
|
280
|
-
|
288
|
+
desc "Recreate the databases from the structure.sql file"
|
281
289
|
task :load => [:environment, :load_config] do
|
282
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
290
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['DB_STRUCTURE'])
|
283
291
|
end
|
284
292
|
|
285
293
|
task :load_if_sql => ['db:create', :environment] do
|
@@ -297,7 +305,7 @@ db_namespace = namespace :db do
|
|
297
305
|
end
|
298
306
|
|
299
307
|
# desc "Recreate the test database from the current schema"
|
300
|
-
task :load => %w(db:test:
|
308
|
+
task :load => %w(db:test:purge) do
|
301
309
|
case ActiveRecord::Base.schema_format
|
302
310
|
when :ruby
|
303
311
|
db_namespace["test:load_schema"].invoke
|
@@ -307,12 +315,11 @@ db_namespace = namespace :db do
|
|
307
315
|
end
|
308
316
|
|
309
317
|
# desc "Recreate the test database from an existent schema.rb file"
|
310
|
-
task :load_schema => %w(db:test:
|
318
|
+
task :load_schema => %w(db:test:purge) do
|
311
319
|
begin
|
312
320
|
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
|
313
|
-
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
|
314
321
|
ActiveRecord::Schema.verbose = false
|
315
|
-
|
322
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA']
|
316
323
|
ensure
|
317
324
|
if should_reconnect
|
318
325
|
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env])
|
@@ -321,13 +328,8 @@ db_namespace = namespace :db do
|
|
321
328
|
end
|
322
329
|
|
323
330
|
# desc "Recreate the test database from an existent structure.sql file"
|
324
|
-
task :load_structure => %w(db:test:
|
325
|
-
|
326
|
-
ActiveRecord::Tasks::DatabaseTasks.current_config(:config => ActiveRecord::Base.configurations['test'])
|
327
|
-
db_namespace["structure:load"].invoke
|
328
|
-
ensure
|
329
|
-
ActiveRecord::Tasks::DatabaseTasks.current_config(:config => nil)
|
330
|
-
end
|
331
|
+
task :load_structure => %w(db:test:purge) do
|
332
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA']
|
331
333
|
end
|
332
334
|
|
333
335
|
# desc "Recreate the test database from a fresh schema"
|
@@ -347,12 +349,12 @@ db_namespace = namespace :db do
|
|
347
349
|
task :clone_structure => %w(db:test:deprecated db:structure:dump db:test:load_structure)
|
348
350
|
|
349
351
|
# desc "Empty the test database"
|
350
|
-
task :purge => %w(
|
352
|
+
task :purge => %w(environment load_config) do
|
351
353
|
ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test']
|
352
354
|
end
|
353
355
|
|
354
356
|
# desc 'Check for pending migrations and load the test schema'
|
355
|
-
task :prepare => %w(
|
357
|
+
task :prepare => %w(environment load_config) do
|
356
358
|
unless ActiveRecord::Base.configurations.blank?
|
357
359
|
db_namespace['test:load'].invoke
|
358
360
|
end
|
@@ -366,7 +368,7 @@ namespace :railties do
|
|
366
368
|
task :migrations => :'db:load_config' do
|
367
369
|
to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map {|n| n.strip }
|
368
370
|
railties = {}
|
369
|
-
Rails.application.
|
371
|
+
Rails.application.migration_railties.each do |railtie|
|
370
372
|
next unless to_load == :all || to_load.include?(railtie.railtie_name)
|
371
373
|
|
372
374
|
if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first)
|