activerecord 4.0.13 → 4.1.0.beta1
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 +745 -2700
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record.rb +2 -6
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +0 -4
- data/lib/active_record/associations.rb +87 -43
- data/lib/active_record/associations/alias_tracker.rb +1 -3
- data/lib/active_record/associations/association.rb +8 -16
- data/lib/active_record/associations/association_scope.rb +5 -16
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +78 -54
- data/lib/active_record/associations/builder/belongs_to.rb +91 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -25
- data/lib/active_record/associations/builder/has_many.rb +2 -2
- data/lib/active_record/associations/builder/has_one.rb +5 -7
- data/lib/active_record/associations/builder/singular_association.rb +6 -7
- data/lib/active_record/associations/collection_association.rb +68 -105
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/has_many_association.rb +11 -9
- data/lib/active_record/associations/has_many_through_association.rb +16 -12
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +204 -165
- data/lib/active_record/associations/join_dependency/join_association.rb +43 -101
- data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
- data/lib/active_record/associations/join_helper.rb +2 -11
- data/lib/active_record/associations/preloader.rb +89 -34
- data/lib/active_record/associations/preloader/association.rb +43 -25
- data/lib/active_record/associations/preloader/collection_association.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +58 -26
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/attribute_assignment.rb +5 -2
- data/lib/active_record/attribute_methods.rb +45 -40
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +8 -22
- data/lib/active_record/attribute_methods/primary_key.rb +1 -7
- data/lib/active_record/attribute_methods/read.rb +55 -28
- data/lib/active_record/attribute_methods/serialization.rb +12 -33
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -13
- data/lib/active_record/attribute_methods/write.rb +37 -12
- data/lib/active_record/autosave_association.rb +207 -207
- data/lib/active_record/base.rb +5 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -5
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +84 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +52 -83
- data/lib/active_record/connection_adapters/abstract/transaction.rb +0 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +58 -60
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -4
- data/lib/active_record/connection_adapters/mysql_adapter.rb +16 -15
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +24 -18
- data/lib/active_record/connection_adapters/postgresql/cast.rb +20 -16
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -43
- data/lib/active_record/connection_adapters/postgresql/oid.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +28 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -30
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +92 -75
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +31 -64
- data/lib/active_record/connection_handling.rb +2 -2
- data/lib/active_record/core.rb +22 -43
- data/lib/active_record/counter_cache.rb +7 -7
- data/lib/active_record/enum.rb +100 -0
- data/lib/active_record/errors.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +171 -74
- data/lib/active_record/inheritance.rb +16 -22
- data/lib/active_record/integration.rb +52 -1
- data/lib/active_record/locking/optimistic.rb +7 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -12
- data/lib/active_record/migration.rb +62 -46
- data/lib/active_record/migration/command_recorder.rb +7 -13
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +10 -8
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +3 -3
- data/lib/active_record/persistence.rb +16 -34
- data/lib/active_record/querying.rb +14 -12
- data/lib/active_record/railtie.rb +0 -50
- data/lib/active_record/railties/databases.rake +12 -15
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +189 -75
- data/lib/active_record/relation.rb +69 -94
- data/lib/active_record/relation/batches.rb +57 -23
- data/lib/active_record/relation/calculations.rb +36 -43
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +107 -62
- data/lib/active_record/relation/merger.rb +7 -20
- data/lib/active_record/relation/predicate_builder.rb +57 -38
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/query_methods.rb +110 -98
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +6 -8
- data/lib/active_record/schema_dumper.rb +16 -5
- data/lib/active_record/schema_migration.rb +24 -25
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +8 -29
- data/lib/active_record/store.rb +56 -28
- data/lib/active_record/tasks/database_tasks.rb +8 -4
- data/lib/active_record/timestamp.rb +4 -4
- data/lib/active_record/transactions.rb +8 -10
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -6
- data/lib/active_record/version.rb +1 -1
- data/lib/rails/generators/active_record.rb +2 -8
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- metadata +32 -45
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
- data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
- data/lib/active_record/test_case.rb +0 -102
@@ -32,6 +32,12 @@ module ActiveRecord
|
|
32
32
|
class_attribute :table_name_suffix, instance_writer: false
|
33
33
|
self.table_name_suffix = ""
|
34
34
|
|
35
|
+
##
|
36
|
+
# :singleton-method:
|
37
|
+
# Accessor for the name of the schema migrations table. By default, the value is "schema_migrations"
|
38
|
+
class_attribute :schema_migrations_table_name, instance_accessor: false
|
39
|
+
self.schema_migrations_table_name = "schema_migrations"
|
40
|
+
|
35
41
|
##
|
36
42
|
# :singleton-method:
|
37
43
|
# Indicates whether table names should be the pluralized versions of the corresponding class names.
|
@@ -124,7 +130,7 @@ module ActiveRecord
|
|
124
130
|
@quoted_table_name = nil
|
125
131
|
@arel_table = nil
|
126
132
|
@sequence_name = nil unless defined?(@explicit_sequence_name) && @explicit_sequence_name
|
127
|
-
@relation = Relation.
|
133
|
+
@relation = Relation.create(self, arel_table)
|
128
134
|
end
|
129
135
|
|
130
136
|
# Returns a quoted version of the table name, used to construct SQL statements.
|
@@ -260,19 +266,6 @@ module ActiveRecord
|
|
260
266
|
@content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
|
261
267
|
end
|
262
268
|
|
263
|
-
# Returns a hash of all the methods added to query each of the columns in the table with the name of the method as the key
|
264
|
-
# and true as the value. This makes it possible to do O(1) lookups in respond_to? to check if a given method for attribute
|
265
|
-
# is available.
|
266
|
-
def column_methods_hash #:nodoc:
|
267
|
-
@dynamic_methods_hash ||= column_names.each_with_object(Hash.new(false)) do |attr, methods|
|
268
|
-
attr_name = attr.to_s
|
269
|
-
methods[attr.to_sym] = attr_name
|
270
|
-
methods["#{attr}=".to_sym] = attr_name
|
271
|
-
methods["#{attr}?".to_sym] = attr_name
|
272
|
-
methods["#{attr}_before_type_cast".to_sym] = attr_name
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
269
|
# Resets all the cached information about columns, which will cause them
|
277
270
|
# to be reloaded on the next request.
|
278
271
|
#
|
@@ -230,6 +230,10 @@ module ActiveRecord
|
|
230
230
|
# validates_presence_of :member
|
231
231
|
# end
|
232
232
|
#
|
233
|
+
# Note that if you do not specify the <tt>inverse_of</tt> option, then
|
234
|
+
# Active Record will try to automatically guess the inverse association
|
235
|
+
# based on heuristics.
|
236
|
+
#
|
233
237
|
# For one-to-one nested associations, if you build the new (in-memory)
|
234
238
|
# child object yourself before assignment, then this module will not
|
235
239
|
# overwrite it, e.g.:
|
@@ -302,7 +306,7 @@ module ActiveRecord
|
|
302
306
|
|
303
307
|
attr_names.each do |association_name|
|
304
308
|
if reflection = reflect_on_association(association_name)
|
305
|
-
reflection.
|
309
|
+
reflection.autosave = true
|
306
310
|
add_autosave_association_callbacks(reflection)
|
307
311
|
|
308
312
|
nested_attributes_options = self.nested_attributes_options.dup
|
@@ -331,7 +335,7 @@ module ActiveRecord
|
|
331
335
|
# the helper methods defined below. Makes it seem like the nested
|
332
336
|
# associations are just regular associations.
|
333
337
|
def generate_association_writer(association_name, type)
|
334
|
-
|
338
|
+
generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
|
335
339
|
if method_defined?(:#{association_name}_attributes=)
|
336
340
|
remove_method(:#{association_name}_attributes=)
|
337
341
|
end
|
@@ -461,19 +465,17 @@ module ActiveRecord
|
|
461
465
|
association.build(attributes.except(*UNASSIGNABLE_KEYS))
|
462
466
|
end
|
463
467
|
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
|
464
|
-
unless
|
468
|
+
unless call_reject_if(association_name, attributes)
|
465
469
|
# Make sure we are operating on the actual object which is in the association's
|
466
470
|
# proxy_target array (either by finding it, or adding it if not found)
|
467
|
-
|
468
|
-
|
471
|
+
# Take into account that the proxy_target may have changed due to callbacks
|
472
|
+
target_record = association.target.detect { |record| record.id.to_s == attributes['id'].to_s }
|
469
473
|
if target_record
|
470
474
|
existing_record = target_record
|
471
475
|
else
|
472
|
-
association.add_to_target(existing_record)
|
476
|
+
association.add_to_target(existing_record, :skip_callbacks)
|
473
477
|
end
|
474
|
-
end
|
475
478
|
|
476
|
-
if !call_reject_if(association_name, attributes)
|
477
479
|
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
478
480
|
end
|
479
481
|
else
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
# = Active Record No Touching
|
3
|
+
module NoTouching
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
# Lets you selectively disable calls to `touch` for the
|
8
|
+
# duration of a block.
|
9
|
+
#
|
10
|
+
# ==== Examples
|
11
|
+
# ActiveRecord::Base.no_touching do
|
12
|
+
# Project.first.touch # does nothing
|
13
|
+
# Message.first.touch # does nothing
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# Project.no_touching do
|
17
|
+
# Project.first.touch # does nothing
|
18
|
+
# Message.first.touch # works, but does not touch the associated project
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
def no_touching(&block)
|
22
|
+
NoTouching.apply_to(self, &block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def apply_to(klass) #:nodoc:
|
28
|
+
klasses.push(klass)
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
klasses.pop
|
32
|
+
end
|
33
|
+
|
34
|
+
def applied_to?(klass) #:nodoc:
|
35
|
+
klasses.any? { |k| k >= klass }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def klasses
|
40
|
+
Thread.current[:no_touching_classes] ||= []
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def no_touching?
|
45
|
+
NoTouching.applied_to?(self.class)
|
46
|
+
end
|
47
|
+
|
48
|
+
def touch(*)
|
49
|
+
super unless no_touching?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -39,11 +39,11 @@ module ActiveRecord
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def to_sql
|
42
|
-
|
42
|
+
""
|
43
43
|
end
|
44
44
|
|
45
45
|
def count(*)
|
46
|
-
|
46
|
+
0
|
47
47
|
end
|
48
48
|
|
49
49
|
def sum(*)
|
@@ -54,7 +54,7 @@ module ActiveRecord
|
|
54
54
|
# TODO: Remove _options argument as soon we remove support to
|
55
55
|
# activerecord-deprecated_finders.
|
56
56
|
if operation == :count
|
57
|
-
|
57
|
+
0
|
58
58
|
else
|
59
59
|
nil
|
60
60
|
end
|
@@ -37,7 +37,7 @@ module ActiveRecord
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# Given an attributes hash, +instantiate+ returns a new instance of
|
40
|
-
# the appropriate class.
|
40
|
+
# the appropriate class.
|
41
41
|
#
|
42
42
|
# For example, +Post.all+ may return Comments, Messages, and Emails
|
43
43
|
# by storing the record's subclass in a +type+ attribute. By calling
|
@@ -46,10 +46,10 @@ module ActiveRecord
|
|
46
46
|
#
|
47
47
|
# See +ActiveRecord::Inheritance#discriminate_class_for_record+ to see
|
48
48
|
# how this "single-table" inheritance mapping is implemented.
|
49
|
-
def instantiate(
|
50
|
-
klass = discriminate_class_for_record(
|
49
|
+
def instantiate(record, column_types = {})
|
50
|
+
klass = discriminate_class_for_record(record)
|
51
51
|
column_types = klass.decorate_columns(column_types.dup)
|
52
|
-
klass.allocate.init_with('attributes' =>
|
52
|
+
klass.allocate.init_with('attributes' => record, 'column_types' => column_types)
|
53
53
|
end
|
54
54
|
|
55
55
|
private
|
@@ -64,7 +64,7 @@ module ActiveRecord
|
|
64
64
|
end
|
65
65
|
|
66
66
|
# Returns true if this object hasn't been saved yet -- that is, a record
|
67
|
-
# for the object doesn't exist in the
|
67
|
+
# for the object doesn't exist in the data store yet; otherwise, returns false.
|
68
68
|
def new_record?
|
69
69
|
sync_with_transaction_state
|
70
70
|
@new_record
|
@@ -195,11 +195,7 @@ module ActiveRecord
|
|
195
195
|
# share the same set of attributes.
|
196
196
|
def becomes!(klass)
|
197
197
|
became = becomes(klass)
|
198
|
-
|
199
|
-
if !klass.descends_from_active_record?
|
200
|
-
sti_type = klass.sti_name
|
201
|
-
end
|
202
|
-
became.public_send("#{klass.inheritance_column}=", sti_type)
|
198
|
+
became.public_send("#{klass.inheritance_column}=", klass.sti_name) unless self.class.descends_from_active_record?
|
203
199
|
became
|
204
200
|
end
|
205
201
|
|
@@ -346,7 +342,8 @@ module ActiveRecord
|
|
346
342
|
# # Account Load (1.2ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT 1 [["id", 1]]
|
347
343
|
# # => #<Account id: 1, email: 'account@example.com'>
|
348
344
|
#
|
349
|
-
# Attributes are
|
345
|
+
# Attributes are reloaded from the database, and caches busted, in
|
346
|
+
# particular the associations cache.
|
350
347
|
#
|
351
348
|
# If the record no longer exists in the database <tt>ActiveRecord::RecordNotFound</tt>
|
352
349
|
# is raised. Otherwise, in addition to the in-place modification the method
|
@@ -387,7 +384,7 @@ module ActiveRecord
|
|
387
384
|
|
388
385
|
fresh_object =
|
389
386
|
if options && options[:lock]
|
390
|
-
self.class.unscoped { self.class.lock
|
387
|
+
self.class.unscoped { self.class.lock.find(id) }
|
391
388
|
else
|
392
389
|
self.class.unscoped { self.class.find(id) }
|
393
390
|
end
|
@@ -397,7 +394,6 @@ module ActiveRecord
|
|
397
394
|
@column_types = self.class.column_types
|
398
395
|
@column_types_override = fresh_object.instance_variable_get('@column_types_override')
|
399
396
|
@attributes_cache = {}
|
400
|
-
@new_record = false
|
401
397
|
self
|
402
398
|
end
|
403
399
|
|
@@ -446,11 +442,9 @@ module ActiveRecord
|
|
446
442
|
|
447
443
|
changes[self.class.locking_column] = increment_lock if locking_enabled?
|
448
444
|
|
449
|
-
|
445
|
+
changed_attributes.except!(*changes.keys)
|
450
446
|
primary_key = self.class.primary_key
|
451
447
|
self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
|
452
|
-
else
|
453
|
-
true
|
454
448
|
end
|
455
449
|
end
|
456
450
|
|
@@ -478,36 +472,24 @@ module ActiveRecord
|
|
478
472
|
|
479
473
|
def create_or_update
|
480
474
|
raise ReadOnlyRecord if readonly?
|
481
|
-
result = new_record? ?
|
475
|
+
result = new_record? ? create_record : update_record
|
482
476
|
result != false
|
483
477
|
end
|
484
478
|
|
485
479
|
# Updates the associated record with values matching those of the instance attributes.
|
486
480
|
# Returns the number of affected rows.
|
487
|
-
def
|
488
|
-
|
489
|
-
if
|
481
|
+
def update_record(attribute_names = @attributes.keys)
|
482
|
+
attributes_values = arel_attributes_with_values_for_update(attribute_names)
|
483
|
+
if attributes_values.empty?
|
490
484
|
0
|
491
485
|
else
|
492
|
-
|
493
|
-
column_hash = klass.connection.schema_cache.columns_hash klass.table_name
|
494
|
-
db_columns_with_values = attributes_with_values.map { |attr,value|
|
495
|
-
real_column = column_hash[attr.name]
|
496
|
-
[real_column, value]
|
497
|
-
}
|
498
|
-
bind_attrs = attributes_with_values.dup
|
499
|
-
bind_attrs.keys.each_with_index do |column, i|
|
500
|
-
real_column = db_columns_with_values[i].first
|
501
|
-
bind_attrs[column] = klass.connection.substitute_at(real_column, i)
|
502
|
-
end
|
503
|
-
stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id_was || id)).arel.compile_update(bind_attrs)
|
504
|
-
klass.connection.update stmt, 'SQL', db_columns_with_values
|
486
|
+
self.class.unscoped.update_record attributes_values, id, id_was
|
505
487
|
end
|
506
488
|
end
|
507
489
|
|
508
490
|
# Creates a record with values matching those of the instance attributes
|
509
491
|
# and returns its id.
|
510
|
-
def
|
492
|
+
def create_record(attribute_names = @attributes.keys)
|
511
493
|
attributes_values = arel_attributes_with_values_for_create(attribute_names)
|
512
494
|
|
513
495
|
new_id = self.class.unscoped.insert attributes_values
|
@@ -1,20 +1,21 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Querying
|
3
|
-
delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :
|
4
|
-
delegate :first_or_create, :first_or_create!, :first_or_initialize, :
|
5
|
-
delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, :
|
6
|
-
delegate :find_by, :find_by!, :
|
7
|
-
delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :
|
8
|
-
delegate :find_each, :find_in_batches, :
|
3
|
+
delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, to: :all
|
4
|
+
delegate :first_or_create, :first_or_create!, :first_or_initialize, to: :all
|
5
|
+
delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, to: :all
|
6
|
+
delegate :find_by, :find_by!, to: :all
|
7
|
+
delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, to: :all
|
8
|
+
delegate :find_each, :find_in_batches, to: :all
|
9
9
|
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
|
10
|
-
:where, :preload, :eager_load, :includes, :from, :lock, :readonly,
|
11
|
-
:having, :create_with, :uniq, :distinct, :references, :none, :unscope, :
|
12
|
-
delegate :count, :average, :minimum, :maximum, :sum, :calculate, :
|
10
|
+
:where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly,
|
11
|
+
:having, :create_with, :uniq, :distinct, :references, :none, :unscope, to: :all
|
12
|
+
delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all
|
13
|
+
delegate :pluck, :ids, to: :all
|
13
14
|
|
14
15
|
# Executes a custom SQL query against your database and returns all the results. The results will
|
15
16
|
# be returned as an array with columns requested encapsulated as attributes of the model you call
|
16
17
|
# this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in
|
17
|
-
# a Product object with the attributes you specified in the SQL query.
|
18
|
+
# a +Product+ object with the attributes you specified in the SQL query.
|
18
19
|
#
|
19
20
|
# If you call a complicated SQL query which spans multiple tables the columns specified by the
|
20
21
|
# SELECT will be attributes of the model, whether or not they are columns of the corresponding
|
@@ -29,9 +30,10 @@ module ActiveRecord
|
|
29
30
|
# Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
|
30
31
|
# # => [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
|
31
32
|
#
|
32
|
-
#
|
33
|
+
# You can use the same string replacement techniques as you can with <tt>ActiveRecord::QueryMethods#where</tt>:
|
34
|
+
#
|
33
35
|
# Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
|
34
|
-
#
|
36
|
+
# Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
|
35
37
|
def find_by_sql(sql, binds = [])
|
36
38
|
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds)
|
37
39
|
column_types = {}
|
@@ -112,56 +112,6 @@ module ActiveRecord
|
|
112
112
|
|
113
113
|
initializer "active_record.set_configs" do |app|
|
114
114
|
ActiveSupport.on_load(:active_record) do
|
115
|
-
begin
|
116
|
-
old_behavior, ActiveSupport::Deprecation.behavior = ActiveSupport::Deprecation.behavior, :stderr
|
117
|
-
whitelist_attributes = app.config.active_record.delete(:whitelist_attributes)
|
118
|
-
|
119
|
-
if respond_to?(:mass_assignment_sanitizer=)
|
120
|
-
mass_assignment_sanitizer = nil
|
121
|
-
else
|
122
|
-
mass_assignment_sanitizer = app.config.active_record.delete(:mass_assignment_sanitizer)
|
123
|
-
end
|
124
|
-
|
125
|
-
unless whitelist_attributes.nil? && mass_assignment_sanitizer.nil?
|
126
|
-
ActiveSupport::Deprecation.warn <<-EOF.strip_heredoc, []
|
127
|
-
Model based mass assignment security has been extracted
|
128
|
-
out of Rails into a gem. Please use the new recommended protection model for
|
129
|
-
params or add `protected_attributes` to your Gemfile to use the old one.
|
130
|
-
|
131
|
-
To disable this message remove the `whitelist_attributes` option from your
|
132
|
-
`config/application.rb` file and any `mass_assignment_sanitizer` options
|
133
|
-
from your `config/environments/*.rb` files.
|
134
|
-
|
135
|
-
See http://guides.rubyonrails.org/security.html#mass-assignment for more information.
|
136
|
-
EOF
|
137
|
-
end
|
138
|
-
|
139
|
-
unless app.config.active_record.delete(:auto_explain_threshold_in_seconds).nil?
|
140
|
-
ActiveSupport::Deprecation.warn <<-EOF.strip_heredoc, []
|
141
|
-
The Active Record auto explain feature has been removed.
|
142
|
-
|
143
|
-
To disable this message remove the `active_record.auto_explain_threshold_in_seconds`
|
144
|
-
option from the `config/environments/*.rb` config file.
|
145
|
-
|
146
|
-
See http://guides.rubyonrails.org/4_0_release_notes.html for more information.
|
147
|
-
EOF
|
148
|
-
end
|
149
|
-
|
150
|
-
unless app.config.active_record.delete(:observers).nil?
|
151
|
-
ActiveSupport::Deprecation.warn <<-EOF.strip_heredoc, []
|
152
|
-
Active Record Observers has been extracted out of Rails into a gem.
|
153
|
-
Please use callbacks or add `rails-observers` to your Gemfile to use observers.
|
154
|
-
|
155
|
-
To disable this message remove the `observers` option from your
|
156
|
-
`config/application.rb` or from your initializers.
|
157
|
-
|
158
|
-
See http://guides.rubyonrails.org/4_0_release_notes.html for more information.
|
159
|
-
EOF
|
160
|
-
end
|
161
|
-
ensure
|
162
|
-
ActiveSupport::Deprecation.behavior = old_behavior
|
163
|
-
end
|
164
|
-
|
165
115
|
app.config.active_record.each do |k,v|
|
166
116
|
send "#{k}=", v
|
167
117
|
end
|
@@ -12,7 +12,7 @@ db_namespace = namespace :db do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
desc 'Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all
|
15
|
+
desc 'Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all databases in the config)'
|
16
16
|
task :create => [:load_config] do
|
17
17
|
if ENV['DATABASE_URL']
|
18
18
|
ActiveRecord::Tasks::DatabaseTasks.create_database_url
|
@@ -95,15 +95,14 @@ db_namespace = namespace :db do
|
|
95
95
|
next # means "return" for rake task
|
96
96
|
end
|
97
97
|
db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
|
98
|
-
db_list.map! { |version|
|
98
|
+
db_list.map! { |version| "%.3d" % version }
|
99
99
|
file_list = []
|
100
100
|
ActiveRecord::Migrator.migrations_paths.each do |path|
|
101
101
|
Dir.foreach(path) do |file|
|
102
102
|
# match "20091231235959_some_name.rb" and "001_some_name.rb" pattern
|
103
103
|
if match_data = /^(\d{3,})_(.+)\.rb$/.match(file)
|
104
|
-
|
105
|
-
status
|
106
|
-
file_list << [status, version, match_data[2].humanize]
|
104
|
+
status = db_list.delete(match_data[1]) ? 'up' : 'down'
|
105
|
+
file_list << [status, match_data[1], match_data[2].humanize]
|
107
106
|
end
|
108
107
|
end
|
109
108
|
end
|
@@ -173,7 +172,7 @@ db_namespace = namespace :db do
|
|
173
172
|
end
|
174
173
|
end
|
175
174
|
|
176
|
-
desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the
|
175
|
+
desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the database first)'
|
177
176
|
task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed]
|
178
177
|
|
179
178
|
desc 'Load the seed data from db/seeds.rb'
|
@@ -237,7 +236,7 @@ db_namespace = namespace :db do
|
|
237
236
|
end
|
238
237
|
|
239
238
|
namespace :schema do
|
240
|
-
desc 'Create a db/schema.rb file that
|
239
|
+
desc 'Create a db/schema.rb file that is portable against any DB supported by AR'
|
241
240
|
task :dump => [:environment, :load_config] do
|
242
241
|
require 'active_record/schema_dumper'
|
243
242
|
filename = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
|
@@ -250,11 +249,8 @@ db_namespace = namespace :db do
|
|
250
249
|
desc 'Load a schema.rb file into the database'
|
251
250
|
task :load => [:environment, :load_config] do
|
252
251
|
file = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
|
253
|
-
|
254
|
-
|
255
|
-
else
|
256
|
-
abort %{#{file} doesn't exist yet. Run `rake db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.}
|
257
|
-
end
|
252
|
+
ActiveRecord::Tasks::DatabaseTasks.check_schema_file(file)
|
253
|
+
load(file)
|
258
254
|
end
|
259
255
|
|
260
256
|
task :load_if_ruby => ['db:create', :environment] do
|
@@ -288,10 +284,10 @@ db_namespace = namespace :db do
|
|
288
284
|
current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
|
289
285
|
ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
|
290
286
|
|
291
|
-
if ActiveRecord::Base.connection.supports_migrations?
|
292
|
-
ActiveRecord::SchemaMigration.table_exists?
|
287
|
+
if ActiveRecord::Base.connection.supports_migrations?
|
293
288
|
File.open(filename, "a") do |f|
|
294
289
|
f.puts ActiveRecord::Base.connection.dump_schema_information
|
290
|
+
f.print "\n"
|
295
291
|
end
|
296
292
|
end
|
297
293
|
db_namespace['structure:dump'].reenable
|
@@ -300,6 +296,7 @@ db_namespace = namespace :db do
|
|
300
296
|
# desc "Recreate the databases from the structure.sql file"
|
301
297
|
task :load => [:environment, :load_config] do
|
302
298
|
filename = ENV['DB_STRUCTURE'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
|
299
|
+
ActiveRecord::Tasks::DatabaseTasks.check_schema_file(filename)
|
303
300
|
current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
|
304
301
|
ActiveRecord::Tasks::DatabaseTasks.structure_load(current_config, filename)
|
305
302
|
end
|
@@ -381,7 +378,7 @@ namespace :railties do
|
|
381
378
|
task :migrations => :'db:load_config' do
|
382
379
|
to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map {|n| n.strip }
|
383
380
|
railties = {}
|
384
|
-
Rails.application.
|
381
|
+
Rails.application.railties.each do |railtie|
|
385
382
|
next unless to_load == :all || to_load.include?(railtie.railtie_name)
|
386
383
|
|
387
384
|
if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first)
|