activerecord 6.0.0 → 6.1.4
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 +1178 -600
- 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 +30 -10
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +55 -29
- 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 +25 -8
- 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 +77 -42
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/preloader.rb +13 -8
- 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 +120 -13
- 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 +63 -44
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
- 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 +141 -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 +76 -79
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
- 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 +17 -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 +83 -65
- data/lib/active_record/connection_adapters/schema_cache.rb +106 -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 +61 -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 +219 -81
- data/lib/active_record/core.rb +268 -71
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -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 +124 -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 +43 -10
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -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 +14 -14
- 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 +71 -20
- 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 +120 -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 +55 -17
- 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 +344 -181
- 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 -82
- 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 +3 -3
- 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 +79 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +26 -73
- 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 +15 -12
- 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 +27 -24
- 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,10 +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
650
|
self
|
633
651
|
end
|
634
652
|
|
@@ -659,7 +677,9 @@ module ActiveRecord
|
|
659
677
|
end
|
660
678
|
|
661
679
|
def scope_for_create
|
662
|
-
|
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
|
663
683
|
end
|
664
684
|
|
665
685
|
# Returns true if relation needs eager loading.
|
@@ -703,7 +723,7 @@ module ActiveRecord
|
|
703
723
|
end
|
704
724
|
|
705
725
|
def inspect
|
706
|
-
subject = loaded? ? records :
|
726
|
+
subject = loaded? ? records : annotate("loading for inspect")
|
707
727
|
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
|
708
728
|
|
709
729
|
entries[10] = "..." if entries.size == 11
|
@@ -720,25 +740,31 @@ module ActiveRecord
|
|
720
740
|
end
|
721
741
|
|
722
742
|
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
723
|
-
|
724
|
-
|
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
|
725
754
|
end
|
726
755
|
|
727
756
|
def preload_associations(records) # :nodoc:
|
728
757
|
preload = preload_values
|
729
758
|
preload += includes_values unless eager_loading?
|
730
759
|
preloader = nil
|
760
|
+
scope = strict_loading_value ? StrictLoadingScope : nil
|
731
761
|
preload.each do |associations|
|
732
762
|
preloader ||= build_preloader
|
733
|
-
preloader.preload records, associations
|
763
|
+
preloader.preload records, associations, scope
|
734
764
|
end
|
735
765
|
end
|
736
766
|
|
737
|
-
attr_reader :_deprecated_scope_source # :nodoc:
|
738
|
-
|
739
767
|
protected
|
740
|
-
attr_writer :_deprecated_scope_source # :nodoc:
|
741
|
-
|
742
768
|
def load_records(records)
|
743
769
|
@records = records.freeze
|
744
770
|
@loaded = true
|
@@ -750,23 +776,29 @@ module ActiveRecord
|
|
750
776
|
|
751
777
|
private
|
752
778
|
def already_in_scope?
|
753
|
-
@delegate_to_klass &&
|
754
|
-
scope = klass.current_scope(true)
|
755
|
-
scope && !scope._deprecated_scope_source
|
756
|
-
end
|
779
|
+
@delegate_to_klass && klass.current_scope(true)
|
757
780
|
end
|
758
781
|
|
759
|
-
def
|
760
|
-
|
761
|
-
end
|
762
|
-
|
763
|
-
def _deprecated_scope_block(name, &block)
|
782
|
+
def current_scope_restoring_block(&block)
|
783
|
+
current_scope = klass.current_scope(true)
|
764
784
|
-> record do
|
765
|
-
klass.current_scope =
|
785
|
+
klass.current_scope = current_scope
|
766
786
|
yield record if block_given?
|
767
787
|
end
|
768
788
|
end
|
769
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
|
+
|
770
802
|
def _scoping(scope)
|
771
803
|
previous, klass.current_scope = klass.current_scope(true), scope
|
772
804
|
yield
|
@@ -776,7 +808,7 @@ module ActiveRecord
|
|
776
808
|
|
777
809
|
def _substitute_values(values)
|
778
810
|
values.map do |name, value|
|
779
|
-
attr =
|
811
|
+
attr = table[name]
|
780
812
|
unless Arel.arel_node?(value)
|
781
813
|
type = klass.type_for_attribute(attr.name)
|
782
814
|
value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
|
@@ -794,27 +826,29 @@ module ActiveRecord
|
|
794
826
|
|
795
827
|
def exec_queries(&block)
|
796
828
|
skip_query_cache_if_necessary do
|
797
|
-
|
798
|
-
if
|
829
|
+
records =
|
830
|
+
if where_clause.contradiction?
|
831
|
+
[]
|
832
|
+
elsif eager_loading?
|
799
833
|
apply_join_dependency do |relation, join_dependency|
|
800
834
|
if relation.null_relation?
|
801
835
|
[]
|
802
836
|
else
|
803
837
|
relation = join_dependency.apply_column_aliases(relation)
|
804
838
|
rows = connection.select_all(relation.arel, "SQL")
|
805
|
-
join_dependency.instantiate(rows, &block)
|
839
|
+
join_dependency.instantiate(rows, strict_loading_value, &block)
|
806
840
|
end.freeze
|
807
841
|
end
|
808
842
|
else
|
809
843
|
klass.find_by_sql(arel, &block).freeze
|
810
844
|
end
|
811
845
|
|
812
|
-
preload_associations(
|
846
|
+
preload_associations(records) unless skip_preloading_value
|
813
847
|
|
814
|
-
|
848
|
+
records.each(&:readonly!) if readonly_value
|
849
|
+
records.each(&:strict_loading!) if strict_loading_value
|
815
850
|
|
816
|
-
|
817
|
-
@records
|
851
|
+
records
|
818
852
|
end
|
819
853
|
end
|
820
854
|
|
@@ -833,27 +867,27 @@ module ActiveRecord
|
|
833
867
|
end
|
834
868
|
|
835
869
|
def references_eager_loaded_tables?
|
836
|
-
joined_tables =
|
870
|
+
joined_tables = build_joins([]).flat_map do |join|
|
837
871
|
if join.is_a?(Arel::Nodes::StringJoin)
|
838
872
|
tables_in_string(join.left)
|
839
873
|
else
|
840
|
-
|
874
|
+
join.left.name
|
841
875
|
end
|
842
876
|
end
|
843
877
|
|
844
|
-
joined_tables
|
878
|
+
joined_tables << table.name
|
845
879
|
|
846
880
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
847
|
-
joined_tables
|
881
|
+
joined_tables.map!(&:downcase)
|
848
882
|
|
849
|
-
(references_values - joined_tables).
|
883
|
+
!(references_values.map(&:to_s) - joined_tables).empty?
|
850
884
|
end
|
851
885
|
|
852
886
|
def tables_in_string(string)
|
853
887
|
return [] if string.blank?
|
854
888
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
855
889
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
856
|
-
string.scan(/
|
890
|
+
string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
|
857
891
|
end
|
858
892
|
end
|
859
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
|