activerecord 6.0.1 → 6.1.7
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 +1314 -633
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/active_record/aggregations.rb +5 -6
- data/lib/active_record/association_relation.rb +26 -15
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +55 -37
- data/lib/active_record/associations/association_scope.rb +19 -15
- data/lib/active_record/associations/belongs_to_association.rb +23 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +38 -13
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +73 -42
- data/lib/active_record/associations/preloader/association.rb +49 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/preloader.rb +12 -7
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +119 -12
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +33 -9
- data/lib/active_record/autosave_association.rb +56 -41
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +24 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +190 -136
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -38
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +145 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
- data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
- data/lib/active_record/connection_adapters/abstract_adapter.rb +63 -77
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +80 -66
- data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +57 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +218 -87
- data/lib/active_record/core.rb +269 -68
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- data/lib/active_record/database_configurations.rb +125 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +80 -38
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +58 -12
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +42 -9
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +18 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +33 -18
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +28 -9
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +75 -21
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +115 -85
- data/lib/active_record/model_schema.rb +117 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +280 -99
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/calculations.rb +106 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +45 -16
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +59 -40
- data/lib/active_record/relation/query_methods.rb +339 -188
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +111 -62
- data/lib/active_record/relation.rb +116 -83
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +1 -4
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +9 -4
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -36
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +87 -20
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +25 -72
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -9
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +30 -29
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
:order, :joins, :left_outer_joins, :references,
|
8
8
|
:extending, :unscope, :optimizer_hints, :annotate]
|
9
9
|
|
10
|
-
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
|
10
|
+
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
|
11
11
|
:reverse_order, :distinct, :create_with, :skip_query_cache]
|
12
12
|
|
13
13
|
CLAUSE_METHODS = [:where, :having, :from]
|
@@ -28,7 +28,6 @@ module ActiveRecord
|
|
28
28
|
@klass = klass
|
29
29
|
@table = table
|
30
30
|
@values = values
|
31
|
-
@offsets = {}
|
32
31
|
@loaded = false
|
33
32
|
@predicate_builder = predicate_builder
|
34
33
|
@delegate_to_klass = false
|
@@ -40,8 +39,9 @@ module ActiveRecord
|
|
40
39
|
end
|
41
40
|
|
42
41
|
def arel_attribute(name) # :nodoc:
|
43
|
-
|
42
|
+
table[name]
|
44
43
|
end
|
44
|
+
deprecate :arel_attribute
|
45
45
|
|
46
46
|
def bind_attribute(name, value) # :nodoc:
|
47
47
|
if reflection = klass._reflect_on_association(name)
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
|
50
50
|
end
|
51
51
|
|
52
|
-
attr =
|
52
|
+
attr = table[name]
|
53
53
|
bind = predicate_builder.build_bind_attribute(attr.name, value)
|
54
54
|
yield attr, bind
|
55
55
|
end
|
@@ -67,10 +67,9 @@ module ActiveRecord
|
|
67
67
|
# user = users.new { |user| user.name = 'Oscar' }
|
68
68
|
# user.name # => Oscar
|
69
69
|
def new(attributes = nil, &block)
|
70
|
-
block =
|
71
|
-
scoping {
|
70
|
+
block = current_scope_restoring_block(&block)
|
71
|
+
scoping { _new(attributes, &block) }
|
72
72
|
end
|
73
|
-
|
74
73
|
alias build new
|
75
74
|
|
76
75
|
# Tries to create a new record with the same scoped attributes
|
@@ -96,8 +95,8 @@ module ActiveRecord
|
|
96
95
|
if attributes.is_a?(Array)
|
97
96
|
attributes.collect { |attr| create(attr, &block) }
|
98
97
|
else
|
99
|
-
block =
|
100
|
-
scoping {
|
98
|
+
block = current_scope_restoring_block(&block)
|
99
|
+
scoping { _create(attributes, &block) }
|
101
100
|
end
|
102
101
|
end
|
103
102
|
|
@@ -111,8 +110,8 @@ module ActiveRecord
|
|
111
110
|
if attributes.is_a?(Array)
|
112
111
|
attributes.collect { |attr| create!(attr, &block) }
|
113
112
|
else
|
114
|
-
block =
|
115
|
-
scoping {
|
113
|
+
block = current_scope_restoring_block(&block)
|
114
|
+
scoping { _create!(attributes, &block) }
|
116
115
|
end
|
117
116
|
end
|
118
117
|
|
@@ -308,7 +307,7 @@ module ActiveRecord
|
|
308
307
|
# last updated record.
|
309
308
|
#
|
310
309
|
# Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
|
311
|
-
def cache_key(timestamp_column =
|
310
|
+
def cache_key(timestamp_column = "updated_at")
|
312
311
|
@cache_keys ||= {}
|
313
312
|
@cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
|
314
313
|
end
|
@@ -317,7 +316,7 @@ module ActiveRecord
|
|
317
316
|
query_signature = ActiveSupport::Digest.hexdigest(to_sql)
|
318
317
|
key = "#{klass.model_name.cache_key}/query-#{query_signature}"
|
319
318
|
|
320
|
-
if
|
319
|
+
if collection_cache_versioning
|
321
320
|
key
|
322
321
|
else
|
323
322
|
"#{key}-#{compute_cache_version(timestamp_column)}"
|
@@ -343,15 +342,17 @@ module ActiveRecord
|
|
343
342
|
end
|
344
343
|
|
345
344
|
def compute_cache_version(timestamp_column) # :nodoc:
|
345
|
+
timestamp_column = timestamp_column.to_s
|
346
|
+
|
346
347
|
if loaded? || distinct_value
|
347
348
|
size = records.size
|
348
349
|
if size > 0
|
349
|
-
timestamp =
|
350
|
+
timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
|
350
351
|
end
|
351
352
|
else
|
352
353
|
collection = eager_loading? ? apply_join_dependency : self
|
353
354
|
|
354
|
-
column = connection.visitor.compile(
|
355
|
+
column = connection.visitor.compile(table[timestamp_column])
|
355
356
|
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
|
356
357
|
|
357
358
|
if collection.has_limit_or_offset?
|
@@ -365,14 +366,12 @@ module ActiveRecord
|
|
365
366
|
arel = query.arel
|
366
367
|
end
|
367
368
|
|
368
|
-
|
369
|
+
size, timestamp = connection.select_rows(arel, nil).first
|
369
370
|
|
370
|
-
if
|
371
|
+
if size
|
371
372
|
column_type = klass.type_for_attribute(timestamp_column)
|
372
|
-
timestamp = column_type.deserialize(
|
373
|
-
size = result["size"]
|
373
|
+
timestamp = column_type.deserialize(timestamp)
|
374
374
|
else
|
375
|
-
timestamp = nil
|
376
375
|
size = 0
|
377
376
|
end
|
378
377
|
end
|
@@ -385,6 +384,15 @@ module ActiveRecord
|
|
385
384
|
end
|
386
385
|
private :compute_cache_version
|
387
386
|
|
387
|
+
# Returns a cache key along with the version.
|
388
|
+
def cache_key_with_version
|
389
|
+
if version = cache_version
|
390
|
+
"#{cache_key}-#{version}"
|
391
|
+
else
|
392
|
+
cache_key
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
388
396
|
# Scope all queries to the current scope.
|
389
397
|
#
|
390
398
|
# Comment.where(post_id: 1).scoping do
|
@@ -398,9 +406,9 @@ module ActiveRecord
|
|
398
406
|
already_in_scope? ? yield : _scoping(self) { yield }
|
399
407
|
end
|
400
408
|
|
401
|
-
def _exec_scope(
|
409
|
+
def _exec_scope(*args, &block) # :nodoc:
|
402
410
|
@delegate_to_klass = true
|
403
|
-
_scoping(
|
411
|
+
_scoping(nil) { instance_exec(*args, &block) || self }
|
404
412
|
ensure
|
405
413
|
@delegate_to_klass = false
|
406
414
|
end
|
@@ -408,7 +416,7 @@ module ActiveRecord
|
|
408
416
|
# Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
|
409
417
|
# statement and sends it straight to the database. It does not instantiate the involved models and it does not
|
410
418
|
# trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
|
411
|
-
# Active Record's normal type casting and serialization.
|
419
|
+
# Active Record's normal type casting and serialization. Returns the number of rows affected.
|
412
420
|
#
|
413
421
|
# Note: As Active Record callbacks are not triggered, this method will not automatically update +updated_at+/+updated_on+ columns.
|
414
422
|
#
|
@@ -432,14 +440,12 @@ module ActiveRecord
|
|
432
440
|
def update_all(updates)
|
433
441
|
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
434
442
|
|
435
|
-
|
436
|
-
|
437
|
-
return relation.update_all(updates)
|
438
|
-
end
|
443
|
+
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
444
|
+
arel.source.left = table
|
439
445
|
|
440
446
|
stmt = Arel::UpdateManager.new
|
441
|
-
stmt.table(arel.
|
442
|
-
stmt.key =
|
447
|
+
stmt.table(arel.source)
|
448
|
+
stmt.key = table[primary_key]
|
443
449
|
stmt.take(arel.limit)
|
444
450
|
stmt.offset(arel.offset)
|
445
451
|
stmt.order(*arel.orders)
|
@@ -449,7 +455,7 @@ module ActiveRecord
|
|
449
455
|
if klass.locking_enabled? &&
|
450
456
|
!updates.key?(klass.locking_column) &&
|
451
457
|
!updates.key?(klass.locking_column.to_sym)
|
452
|
-
attr =
|
458
|
+
attr = table[klass.locking_column]
|
453
459
|
updates[attr.name] = _increment_attribute(attr)
|
454
460
|
end
|
455
461
|
stmt.set _substitute_values(updates)
|
@@ -457,7 +463,7 @@ module ActiveRecord
|
|
457
463
|
stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
|
458
464
|
end
|
459
465
|
|
460
|
-
|
466
|
+
klass.connection.update(stmt, "#{klass} Update All").tap { reset }
|
461
467
|
end
|
462
468
|
|
463
469
|
def update(id = :all, attributes) # :nodoc:
|
@@ -468,26 +474,40 @@ module ActiveRecord
|
|
468
474
|
end
|
469
475
|
end
|
470
476
|
|
471
|
-
|
477
|
+
# Updates the counters of the records in the current relation.
|
478
|
+
#
|
479
|
+
# ==== Parameters
|
480
|
+
#
|
481
|
+
# * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
|
482
|
+
# * <tt>:touch</tt> option - Touch the timestamp columns when updating.
|
483
|
+
# * If attributes names are passed, they are updated along with update_at/on attributes.
|
484
|
+
#
|
485
|
+
# ==== Examples
|
486
|
+
#
|
487
|
+
# # For Posts by a given author increment the comment_count by 1.
|
488
|
+
# Post.where(author_id: author.id).update_counters(comment_count: 1)
|
489
|
+
def update_counters(counters)
|
472
490
|
touch = counters.delete(:touch)
|
473
491
|
|
474
492
|
updates = {}
|
475
493
|
counters.each do |counter_name, value|
|
476
|
-
attr =
|
494
|
+
attr = table[counter_name]
|
477
495
|
updates[attr.name] = _increment_attribute(attr, value)
|
478
496
|
end
|
479
497
|
|
480
498
|
if touch
|
481
499
|
names = touch if touch != true
|
482
|
-
|
500
|
+
names = Array.wrap(names)
|
501
|
+
options = names.extract_options!
|
502
|
+
touch_updates = klass.touch_attributes_with_time(*names, **options)
|
483
503
|
updates.merge!(touch_updates) unless touch_updates.empty?
|
484
504
|
end
|
485
505
|
|
486
506
|
update_all updates
|
487
507
|
end
|
488
508
|
|
489
|
-
# Touches all records in the current relation
|
490
|
-
#
|
509
|
+
# Touches all records in the current relation, setting the +updated_at+/+updated_on+ attributes to the current time or the time specified.
|
510
|
+
# It does not instantiate the involved models, and it does not trigger Active Record callbacks or validations.
|
491
511
|
# This method can be passed attribute names and an optional time argument.
|
492
512
|
# If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
|
493
513
|
# If no time argument is passed, the current time is used as default.
|
@@ -560,23 +580,18 @@ module ActiveRecord
|
|
560
580
|
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
561
581
|
end
|
562
582
|
|
563
|
-
|
564
|
-
|
565
|
-
return relation.delete_all
|
566
|
-
end
|
583
|
+
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
584
|
+
arel.source.left = table
|
567
585
|
|
568
586
|
stmt = Arel::DeleteManager.new
|
569
|
-
stmt.from(arel.
|
570
|
-
stmt.key =
|
587
|
+
stmt.from(arel.source)
|
588
|
+
stmt.key = table[primary_key]
|
571
589
|
stmt.take(arel.limit)
|
572
590
|
stmt.offset(arel.offset)
|
573
591
|
stmt.order(*arel.orders)
|
574
592
|
stmt.wheres = arel.constraints
|
575
593
|
|
576
|
-
|
577
|
-
|
578
|
-
reset
|
579
|
-
affected
|
594
|
+
klass.connection.delete(stmt, "#{klass} Destroy").tap { reset }
|
580
595
|
end
|
581
596
|
|
582
597
|
# Finds and destroys all records matching the specified conditions.
|
@@ -612,7 +627,10 @@ module ActiveRecord
|
|
612
627
|
#
|
613
628
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
614
629
|
def load(&block)
|
615
|
-
|
630
|
+
unless loaded?
|
631
|
+
@records = exec_queries(&block)
|
632
|
+
@loaded = true
|
633
|
+
end
|
616
634
|
|
617
635
|
self
|
618
636
|
end
|
@@ -625,11 +643,10 @@ module ActiveRecord
|
|
625
643
|
|
626
644
|
def reset
|
627
645
|
@delegate_to_klass = false
|
628
|
-
@_deprecated_scope_source = nil
|
629
646
|
@to_sql = @arel = @loaded = @should_eager_load = nil
|
647
|
+
@offsets = @take = nil
|
648
|
+
@cache_keys = nil
|
630
649
|
@records = [].freeze
|
631
|
-
@offsets = {}
|
632
|
-
@take = nil
|
633
650
|
self
|
634
651
|
end
|
635
652
|
|
@@ -660,7 +677,9 @@ module ActiveRecord
|
|
660
677
|
end
|
661
678
|
|
662
679
|
def scope_for_create
|
663
|
-
|
680
|
+
hash = where_clause.to_h(klass.table_name, equality_only: true)
|
681
|
+
create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
|
682
|
+
hash
|
664
683
|
end
|
665
684
|
|
666
685
|
# Returns true if relation needs eager loading.
|
@@ -704,7 +723,7 @@ module ActiveRecord
|
|
704
723
|
end
|
705
724
|
|
706
725
|
def inspect
|
707
|
-
subject = loaded? ? records :
|
726
|
+
subject = loaded? ? records : annotate("loading for inspect")
|
708
727
|
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
|
709
728
|
|
710
729
|
entries[10] = "..." if entries.size == 11
|
@@ -721,25 +740,31 @@ module ActiveRecord
|
|
721
740
|
end
|
722
741
|
|
723
742
|
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
724
|
-
|
725
|
-
|
743
|
+
ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
|
744
|
+
end
|
745
|
+
|
746
|
+
class StrictLoadingScope # :nodoc:
|
747
|
+
def self.empty_scope?
|
748
|
+
true
|
749
|
+
end
|
750
|
+
|
751
|
+
def self.strict_loading_value
|
752
|
+
true
|
753
|
+
end
|
726
754
|
end
|
727
755
|
|
728
756
|
def preload_associations(records) # :nodoc:
|
729
757
|
preload = preload_values
|
730
758
|
preload += includes_values unless eager_loading?
|
731
759
|
preloader = nil
|
760
|
+
scope = strict_loading_value ? StrictLoadingScope : nil
|
732
761
|
preload.each do |associations|
|
733
762
|
preloader ||= build_preloader
|
734
|
-
preloader.preload records, associations
|
763
|
+
preloader.preload records, associations, scope
|
735
764
|
end
|
736
765
|
end
|
737
766
|
|
738
|
-
attr_reader :_deprecated_scope_source # :nodoc:
|
739
|
-
|
740
767
|
protected
|
741
|
-
attr_writer :_deprecated_scope_source # :nodoc:
|
742
|
-
|
743
768
|
def load_records(records)
|
744
769
|
@records = records.freeze
|
745
770
|
@loaded = true
|
@@ -751,23 +776,29 @@ module ActiveRecord
|
|
751
776
|
|
752
777
|
private
|
753
778
|
def already_in_scope?
|
754
|
-
@delegate_to_klass &&
|
755
|
-
scope = klass.current_scope(true)
|
756
|
-
scope && !scope._deprecated_scope_source
|
757
|
-
end
|
779
|
+
@delegate_to_klass && klass.current_scope(true)
|
758
780
|
end
|
759
781
|
|
760
|
-
def
|
761
|
-
|
762
|
-
end
|
763
|
-
|
764
|
-
def _deprecated_scope_block(name, &block)
|
782
|
+
def current_scope_restoring_block(&block)
|
783
|
+
current_scope = klass.current_scope(true)
|
765
784
|
-> record do
|
766
|
-
klass.current_scope =
|
785
|
+
klass.current_scope = current_scope
|
767
786
|
yield record if block_given?
|
768
787
|
end
|
769
788
|
end
|
770
789
|
|
790
|
+
def _new(attributes, &block)
|
791
|
+
klass.new(attributes, &block)
|
792
|
+
end
|
793
|
+
|
794
|
+
def _create(attributes, &block)
|
795
|
+
klass.create(attributes, &block)
|
796
|
+
end
|
797
|
+
|
798
|
+
def _create!(attributes, &block)
|
799
|
+
klass.create!(attributes, &block)
|
800
|
+
end
|
801
|
+
|
771
802
|
def _scoping(scope)
|
772
803
|
previous, klass.current_scope = klass.current_scope(true), scope
|
773
804
|
yield
|
@@ -777,7 +808,7 @@ module ActiveRecord
|
|
777
808
|
|
778
809
|
def _substitute_values(values)
|
779
810
|
values.map do |name, value|
|
780
|
-
attr =
|
811
|
+
attr = table[name]
|
781
812
|
unless Arel.arel_node?(value)
|
782
813
|
type = klass.type_for_attribute(attr.name)
|
783
814
|
value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
|
@@ -795,27 +826,29 @@ module ActiveRecord
|
|
795
826
|
|
796
827
|
def exec_queries(&block)
|
797
828
|
skip_query_cache_if_necessary do
|
798
|
-
|
799
|
-
if
|
829
|
+
records =
|
830
|
+
if where_clause.contradiction?
|
831
|
+
[]
|
832
|
+
elsif eager_loading?
|
800
833
|
apply_join_dependency do |relation, join_dependency|
|
801
834
|
if relation.null_relation?
|
802
835
|
[]
|
803
836
|
else
|
804
837
|
relation = join_dependency.apply_column_aliases(relation)
|
805
838
|
rows = connection.select_all(relation.arel, "SQL")
|
806
|
-
join_dependency.instantiate(rows, &block)
|
839
|
+
join_dependency.instantiate(rows, strict_loading_value, &block)
|
807
840
|
end.freeze
|
808
841
|
end
|
809
842
|
else
|
810
843
|
klass.find_by_sql(arel, &block).freeze
|
811
844
|
end
|
812
845
|
|
813
|
-
preload_associations(
|
846
|
+
preload_associations(records) unless skip_preloading_value
|
814
847
|
|
815
|
-
|
848
|
+
records.each(&:readonly!) if readonly_value
|
849
|
+
records.each(&:strict_loading!) if strict_loading_value
|
816
850
|
|
817
|
-
|
818
|
-
@records
|
851
|
+
records
|
819
852
|
end
|
820
853
|
end
|
821
854
|
|
@@ -834,27 +867,27 @@ module ActiveRecord
|
|
834
867
|
end
|
835
868
|
|
836
869
|
def references_eager_loaded_tables?
|
837
|
-
joined_tables =
|
870
|
+
joined_tables = build_joins([]).flat_map do |join|
|
838
871
|
if join.is_a?(Arel::Nodes::StringJoin)
|
839
872
|
tables_in_string(join.left)
|
840
873
|
else
|
841
|
-
|
874
|
+
join.left.name
|
842
875
|
end
|
843
876
|
end
|
844
877
|
|
845
|
-
joined_tables
|
878
|
+
joined_tables << table.name
|
846
879
|
|
847
880
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
848
|
-
joined_tables
|
881
|
+
joined_tables.map!(&:downcase)
|
849
882
|
|
850
|
-
(references_values - joined_tables).
|
883
|
+
!(references_values.map(&:to_s) - joined_tables).empty?
|
851
884
|
end
|
852
885
|
|
853
886
|
def tables_in_string(string)
|
854
887
|
return [] if string.blank?
|
855
888
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
856
889
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
857
|
-
string.scan(/
|
890
|
+
string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
|
858
891
|
end
|
859
892
|
end
|
860
893
|
end
|
data/lib/active_record/result.rb
CHANGED
@@ -65,16 +65,10 @@ module ActiveRecord
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
def to_hash
|
69
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
70
|
-
`ActiveRecord::Result#to_hash` has been renamed to `to_a`.
|
71
|
-
`to_hash` is deprecated and will be removed in Rails 6.1.
|
72
|
-
MSG
|
73
|
-
to_a
|
74
|
-
end
|
75
|
-
|
76
68
|
alias :map! :map
|
77
69
|
alias :collect! :map
|
70
|
+
deprecate "map!": :map
|
71
|
+
deprecate "collect!": :map
|
78
72
|
|
79
73
|
# Returns true if there are no records, otherwise false.
|
80
74
|
def empty?
|
@@ -92,31 +86,30 @@ module ActiveRecord
|
|
92
86
|
hash_rows[idx]
|
93
87
|
end
|
94
88
|
|
95
|
-
# Returns the first record from the rows collection.
|
96
|
-
# If the rows collection is empty, returns +nil+.
|
97
|
-
def first
|
98
|
-
return nil if @rows.empty?
|
99
|
-
Hash[@columns.zip(@rows.first)]
|
100
|
-
end
|
101
|
-
|
102
89
|
# Returns the last record from the rows collection.
|
103
|
-
|
104
|
-
|
105
|
-
return nil if @rows.empty?
|
106
|
-
Hash[@columns.zip(@rows.last)]
|
90
|
+
def last(n = nil)
|
91
|
+
n ? hash_rows.last(n) : hash_rows.last
|
107
92
|
end
|
108
93
|
|
109
94
|
def cast_values(type_overrides = {}) # :nodoc:
|
110
95
|
if columns.one?
|
111
96
|
# Separated to avoid allocating an array per row
|
112
97
|
|
113
|
-
type =
|
98
|
+
type = if type_overrides.is_a?(Array)
|
99
|
+
type_overrides.first
|
100
|
+
else
|
101
|
+
column_type(columns.first, type_overrides)
|
102
|
+
end
|
114
103
|
|
115
104
|
rows.map do |(value)|
|
116
105
|
type.deserialize(value)
|
117
106
|
end
|
118
107
|
else
|
119
|
-
types =
|
108
|
+
types = if type_overrides.is_a?(Array)
|
109
|
+
type_overrides
|
110
|
+
else
|
111
|
+
columns.map { |name| column_type(name, type_overrides) }
|
112
|
+
end
|
120
113
|
|
121
114
|
rows.map do |values|
|
122
115
|
Array.new(values.size) { |i| types[i].deserialize(values[i]) }
|
@@ -132,7 +125,6 @@ module ActiveRecord
|
|
132
125
|
end
|
133
126
|
|
134
127
|
private
|
135
|
-
|
136
128
|
def column_type(name, type_overrides = {})
|
137
129
|
type_overrides.fetch(name) do
|
138
130
|
column_types.fetch(name, Type.default_value)
|
@@ -146,21 +138,36 @@ module ActiveRecord
|
|
146
138
|
# used as keys in ActiveRecord::Base's @attributes hash
|
147
139
|
columns = @columns.map(&:-@)
|
148
140
|
length = columns.length
|
141
|
+
template = nil
|
149
142
|
|
150
143
|
@rows.map { |row|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
144
|
+
if template
|
145
|
+
# We use transform_values to build subsequent rows from the
|
146
|
+
# hash of the first row. This is faster because we avoid any
|
147
|
+
# reallocs and in Ruby 2.7+ avoid hashing entirely.
|
148
|
+
index = -1
|
149
|
+
template.transform_values do
|
150
|
+
row[index += 1]
|
151
|
+
end
|
152
|
+
else
|
153
|
+
# In the past we used Hash[columns.zip(row)]
|
154
|
+
# though elegant, the verbose way is much more efficient
|
155
|
+
# both time and memory wise cause it avoids a big array allocation
|
156
|
+
# this method is called a lot and needs to be micro optimised
|
157
|
+
hash = {}
|
158
|
+
|
159
|
+
index = 0
|
160
|
+
while index < length
|
161
|
+
hash[columns[index]] = row[index]
|
162
|
+
index += 1
|
163
|
+
end
|
164
|
+
|
165
|
+
# It's possible to select the same column twice, in which case
|
166
|
+
# we can't use a template
|
167
|
+
template = hash if hash.length == length
|
168
|
+
|
169
|
+
hash
|
161
170
|
end
|
162
|
-
|
163
|
-
hash
|
164
171
|
}
|
165
172
|
end
|
166
173
|
end
|
@@ -14,9 +14,9 @@ module ActiveRecord
|
|
14
14
|
class RuntimeRegistry # :nodoc:
|
15
15
|
extend ActiveSupport::PerThreadRegistry
|
16
16
|
|
17
|
-
attr_accessor :
|
17
|
+
attr_accessor :sql_runtime
|
18
18
|
|
19
|
-
[:
|
19
|
+
[:sql_runtime].each do |val|
|
20
20
|
class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
|
21
21
|
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
22
22
|
end
|
@@ -67,7 +67,7 @@ module ActiveRecord
|
|
67
67
|
)
|
68
68
|
|
69
69
|
# Ensure we aren't dealing with a subclass of String that might
|
70
|
-
# override methods we use (
|
70
|
+
# override methods we use (e.g. Arel::Nodes::SqlLiteral).
|
71
71
|
if condition.first.kind_of?(String) && !condition.first.instance_of?(String)
|
72
72
|
condition = [String.new(condition.first), *condition[1..-1]]
|
73
73
|
end
|
@@ -141,19 +141,7 @@ module ActiveRecord
|
|
141
141
|
(unexpected ||= []) << arg
|
142
142
|
end
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
if allow_unsafe_raw_sql == :deprecated
|
147
|
-
ActiveSupport::Deprecation.warn(
|
148
|
-
"Dangerous query method (method whose arguments are used as raw " \
|
149
|
-
"SQL) called with non-attribute argument(s): " \
|
150
|
-
"#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
|
151
|
-
"arguments will be disallowed in Rails 6.1. This method should " \
|
152
|
-
"not be called with user-provided values, such as request " \
|
153
|
-
"parameters or model attributes. Known-safe values can be passed " \
|
154
|
-
"by wrapping them in Arel.sql()."
|
155
|
-
)
|
156
|
-
else
|
144
|
+
if unexpected
|
157
145
|
raise(ActiveRecord::UnknownAttributeReference,
|
158
146
|
"Query method called with non-attribute argument(s): " +
|
159
147
|
unexpected.map(&:inspect).join(", ")
|
@@ -193,13 +181,14 @@ module ActiveRecord
|
|
193
181
|
|
194
182
|
def quote_bound_value(value, c = connection)
|
195
183
|
if value.respond_to?(:map) && !value.acts_like?(:string)
|
196
|
-
|
197
|
-
if
|
184
|
+
values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
|
185
|
+
if values.empty?
|
198
186
|
c.quote(nil)
|
199
187
|
else
|
200
|
-
|
188
|
+
values.map! { |v| c.quote(v) }.join(",")
|
201
189
|
end
|
202
190
|
else
|
191
|
+
value = value.id_for_database if value.respond_to?(:id_for_database)
|
203
192
|
c.quote(value)
|
204
193
|
end
|
205
194
|
end
|