activerecord 7.0.6 → 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1424 -1390
- data/MIT-LICENSE +1 -1
- data/README.rdoc +15 -16
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +16 -10
- data/lib/active_record/associations/collection_proxy.rb +20 -10
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +6 -8
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +295 -199
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +40 -26
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +105 -21
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +60 -18
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +10 -24
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +128 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -124
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +496 -102
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +214 -113
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -144
- data/lib/active_record/connection_adapters/mysql/quoting.rb +21 -14
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +18 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +71 -40
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +15 -8
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +349 -55
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +338 -176
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +45 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +9 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +210 -83
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +71 -94
- data/lib/active_record/core.rb +136 -148
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +8 -3
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +36 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +113 -26
- data/lib/active_record/errors.rb +108 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +119 -71
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +55 -8
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +120 -30
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +5 -7
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +104 -5
- data/lib/active_record/migration/compatibility.rb +142 -58
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration.rb +265 -112
- data/lib/active_record/model_schema.rb +60 -40
- data/lib/active_record/nested_attributes.rb +21 -3
- data/lib/active_record/normalization.rb +159 -0
- data/lib/active_record/persistence.rb +187 -35
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +109 -47
- data/lib/active_record/railties/controller_runtime.rb +12 -8
- data/lib/active_record/railties/databases.rake +139 -145
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +162 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +160 -63
- data/lib/active_record/relation/delegation.rb +22 -8
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -16
- data/lib/active_record/relation/query_attribute.rb +25 -1
- data/lib/active_record/relation/query_methods.rb +378 -70
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +76 -35
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +46 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +7 -5
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +11 -2
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +27 -15
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +39 -13
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +4 -0
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +50 -15
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
data/lib/active_record/core.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/enumerable"
|
4
|
-
require "active_support/core_ext/
|
5
|
-
require "active_support/core_ext/string/filters"
|
4
|
+
require "active_support/core_ext/module/delegation"
|
6
5
|
require "active_support/parameter_filter"
|
7
6
|
require "concurrent/map"
|
8
7
|
|
9
8
|
module ActiveRecord
|
9
|
+
# = Active Record \Core
|
10
10
|
module Core
|
11
11
|
extend ActiveSupport::Concern
|
12
|
+
include ActiveModel::Access
|
12
13
|
|
13
14
|
included do
|
14
15
|
##
|
@@ -19,11 +20,30 @@ module ActiveRecord
|
|
19
20
|
# retrieved on both a class and instance level by calling +logger+.
|
20
21
|
class_attribute :logger, instance_writer: false
|
21
22
|
|
23
|
+
class_attribute :_destroy_association_async_job, instance_accessor: false, default: "ActiveRecord::DestroyAssociationAsyncJob"
|
24
|
+
|
25
|
+
# The job class used to destroy associations in the background.
|
26
|
+
def self.destroy_association_async_job
|
27
|
+
if _destroy_association_async_job.is_a?(String)
|
28
|
+
self._destroy_association_async_job = _destroy_association_async_job.constantize
|
29
|
+
end
|
30
|
+
_destroy_association_async_job
|
31
|
+
rescue NameError => error
|
32
|
+
raise NameError, "Unable to load destroy_association_async_job: #{error.message}"
|
33
|
+
end
|
34
|
+
|
35
|
+
singleton_class.alias_method :destroy_association_async_job=, :_destroy_association_async_job=
|
36
|
+
delegate :destroy_association_async_job, to: :class
|
37
|
+
|
22
38
|
##
|
23
39
|
# :singleton-method:
|
24
40
|
#
|
25
|
-
# Specifies the
|
26
|
-
|
41
|
+
# Specifies the maximum number of records that will be destroyed in a
|
42
|
+
# single background job by the <tt>dependent: :destroy_async</tt>
|
43
|
+
# association option. When +nil+ (default), all dependent records will be
|
44
|
+
# destroyed in a single background job. If specified, the records to be
|
45
|
+
# destroyed will be split into multiple background jobs.
|
46
|
+
class_attribute :destroy_association_async_batch_size, instance_writer: false, instance_predicate: false, default: nil
|
27
47
|
|
28
48
|
##
|
29
49
|
# Contains the database configuration - as is typically stored in config/database.yml -
|
@@ -33,19 +53,19 @@ module ActiveRecord
|
|
33
53
|
#
|
34
54
|
# development:
|
35
55
|
# adapter: sqlite3
|
36
|
-
# database:
|
56
|
+
# database: storage/development.sqlite3
|
37
57
|
#
|
38
58
|
# production:
|
39
59
|
# adapter: sqlite3
|
40
|
-
# database:
|
60
|
+
# database: storage/production.sqlite3
|
41
61
|
#
|
42
62
|
# ...would result in ActiveRecord::Base.configurations to look like this:
|
43
63
|
#
|
44
64
|
# #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
|
45
65
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
|
46
|
-
# @name="primary", @config={adapter: "sqlite3", database: "
|
66
|
+
# @name="primary", @config={adapter: "sqlite3", database: "storage/development.sqlite3"}>,
|
47
67
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
|
48
|
-
# @name="primary", @config={adapter: "sqlite3", database: "
|
68
|
+
# @name="primary", @config={adapter: "sqlite3", database: "storage/production.sqlite3"}>
|
49
69
|
# ]>
|
50
70
|
def self.configurations=(config)
|
51
71
|
@@configurations = ActiveRecord::DatabaseConfigurations.new(config)
|
@@ -71,6 +91,8 @@ module ActiveRecord
|
|
71
91
|
|
72
92
|
class_attribute :has_many_inversing, instance_accessor: false, default: false
|
73
93
|
|
94
|
+
class_attribute :run_commit_callbacks_on_first_saved_instances_in_transaction, instance_accessor: false, default: true
|
95
|
+
|
74
96
|
class_attribute :default_connection_handler, instance_writer: false
|
75
97
|
|
76
98
|
class_attribute :default_role, instance_writer: false
|
@@ -99,33 +121,6 @@ module ActiveRecord
|
|
99
121
|
ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] = handler
|
100
122
|
end
|
101
123
|
|
102
|
-
def self.connection_handlers
|
103
|
-
if ActiveRecord.legacy_connection_handling
|
104
|
-
else
|
105
|
-
raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
|
106
|
-
end
|
107
|
-
|
108
|
-
@@connection_handlers ||= {}
|
109
|
-
end
|
110
|
-
|
111
|
-
def self.connection_handlers=(handlers)
|
112
|
-
if ActiveRecord.legacy_connection_handling
|
113
|
-
ActiveSupport::Deprecation.warn(<<~MSG)
|
114
|
-
Using legacy connection handling is deprecated. Please set
|
115
|
-
`legacy_connection_handling` to `false` in your application.
|
116
|
-
|
117
|
-
The new connection handling does not support `connection_handlers`
|
118
|
-
getter and setter.
|
119
|
-
|
120
|
-
Read more about how to migrate at: https://guides.rubyonrails.org/active_record_multiple_databases.html#migrate-to-the-new-connection-handling
|
121
|
-
MSG
|
122
|
-
else
|
123
|
-
raise NotImplementedError, "The new connection handling does not support multiple connection handlers."
|
124
|
-
end
|
125
|
-
|
126
|
-
@@connection_handlers = handlers
|
127
|
-
end
|
128
|
-
|
129
124
|
def self.asynchronous_queries_session # :nodoc:
|
130
125
|
asynchronous_queries_tracker.current_session
|
131
126
|
end
|
@@ -145,16 +140,12 @@ module ActiveRecord
|
|
145
140
|
# ActiveRecord::Base.current_role #=> :reading
|
146
141
|
# end
|
147
142
|
def self.current_role
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
connected_to_stack.reverse_each do |hash|
|
152
|
-
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
|
153
|
-
return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
|
154
|
-
end
|
155
|
-
|
156
|
-
default_role
|
143
|
+
connected_to_stack.reverse_each do |hash|
|
144
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
|
145
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
|
157
146
|
end
|
147
|
+
|
148
|
+
default_role
|
158
149
|
end
|
159
150
|
|
160
151
|
# Returns the symbol representing the current connected shard.
|
@@ -186,16 +177,12 @@ module ActiveRecord
|
|
186
177
|
# ActiveRecord::Base.current_preventing_writes #=> false
|
187
178
|
# end
|
188
179
|
def self.current_preventing_writes
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
connected_to_stack.reverse_each do |hash|
|
193
|
-
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
|
194
|
-
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
|
195
|
-
end
|
196
|
-
|
197
|
-
false
|
180
|
+
connected_to_stack.reverse_each do |hash|
|
181
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
|
182
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
|
198
183
|
end
|
184
|
+
|
185
|
+
false
|
199
186
|
end
|
200
187
|
|
201
188
|
def self.connected_to_stack # :nodoc:
|
@@ -252,19 +239,6 @@ module ActiveRecord
|
|
252
239
|
@find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
|
253
240
|
end
|
254
241
|
|
255
|
-
def inherited(child_class) # :nodoc:
|
256
|
-
# initialize cache at class definition for thread safety
|
257
|
-
child_class.initialize_find_by_cache
|
258
|
-
unless child_class.base_class?
|
259
|
-
klass = self
|
260
|
-
until klass.base_class?
|
261
|
-
klass.initialize_find_by_cache
|
262
|
-
klass = klass.superclass
|
263
|
-
end
|
264
|
-
end
|
265
|
-
super
|
266
|
-
end
|
267
|
-
|
268
242
|
def find(*ids) # :nodoc:
|
269
243
|
# We don't have cache keys for this stuff yet
|
270
244
|
return super unless ids.length == 1
|
@@ -274,14 +248,8 @@ module ActiveRecord
|
|
274
248
|
|
275
249
|
return super if StatementCache.unsupported_value?(id)
|
276
250
|
|
277
|
-
|
278
|
-
|
279
|
-
statement = cached_find_by_statement(key) { |params|
|
280
|
-
where(key => params.bind).limit(1)
|
281
|
-
}
|
282
|
-
|
283
|
-
statement.execute([id], connection).first ||
|
284
|
-
raise(RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id))
|
251
|
+
cached_find_by([primary_key], [id]) ||
|
252
|
+
raise(RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}", name, primary_key, id))
|
285
253
|
end
|
286
254
|
|
287
255
|
def find_by(*args) # :nodoc:
|
@@ -313,48 +281,13 @@ module ActiveRecord
|
|
313
281
|
h[key] = value
|
314
282
|
end
|
315
283
|
|
316
|
-
keys
|
317
|
-
statement = cached_find_by_statement(keys) { |params|
|
318
|
-
wheres = keys.index_with { params.bind }
|
319
|
-
where(wheres).limit(1)
|
320
|
-
}
|
321
|
-
|
322
|
-
begin
|
323
|
-
statement.execute(hash.values, connection).first
|
324
|
-
rescue TypeError
|
325
|
-
raise ActiveRecord::StatementInvalid
|
326
|
-
end
|
284
|
+
cached_find_by(hash.keys, hash.values)
|
327
285
|
end
|
328
286
|
|
329
287
|
def find_by!(*args) # :nodoc:
|
330
288
|
find_by(*args) || where(*args).raise_record_not_found_exception!
|
331
289
|
end
|
332
290
|
|
333
|
-
%w(
|
334
|
-
reading_role writing_role legacy_connection_handling default_timezone index_nested_attribute_errors
|
335
|
-
verbose_query_logs queues warn_on_records_fetched_greater_than maintain_test_schema
|
336
|
-
application_record_class action_on_strict_loading_violation schema_format error_on_ignored_order
|
337
|
-
timestamped_migrations dump_schema_after_migration dump_schemas suppress_multiple_database_warning
|
338
|
-
).each do |attr|
|
339
|
-
module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
340
|
-
def #{attr}
|
341
|
-
ActiveSupport::Deprecation.warn(<<~MSG)
|
342
|
-
ActiveRecord::Base.#{attr} is deprecated and will be removed in Rails 7.1.
|
343
|
-
Use `ActiveRecord.#{attr}` instead.
|
344
|
-
MSG
|
345
|
-
ActiveRecord.#{attr}
|
346
|
-
end
|
347
|
-
|
348
|
-
def #{attr}=(value)
|
349
|
-
ActiveSupport::Deprecation.warn(<<~MSG)
|
350
|
-
ActiveRecord::Base.#{attr}= is deprecated and will be removed in Rails 7.1.
|
351
|
-
Use `ActiveRecord.#{attr}=` instead.
|
352
|
-
MSG
|
353
|
-
ActiveRecord.#{attr} = value
|
354
|
-
end
|
355
|
-
RUBY
|
356
|
-
end
|
357
|
-
|
358
291
|
def initialize_generated_modules # :nodoc:
|
359
292
|
generated_association_methods
|
360
293
|
end
|
@@ -371,10 +304,10 @@ module ActiveRecord
|
|
371
304
|
|
372
305
|
# Returns columns which shouldn't be exposed while calling +#inspect+.
|
373
306
|
def filter_attributes
|
374
|
-
if
|
375
|
-
@filter_attributes
|
376
|
-
else
|
307
|
+
if @filter_attributes.nil?
|
377
308
|
superclass.filter_attributes
|
309
|
+
else
|
310
|
+
@filter_attributes
|
378
311
|
end
|
379
312
|
end
|
380
313
|
|
@@ -385,13 +318,13 @@ module ActiveRecord
|
|
385
318
|
end
|
386
319
|
|
387
320
|
def inspection_filter # :nodoc:
|
388
|
-
if
|
321
|
+
if @filter_attributes.nil?
|
322
|
+
superclass.inspection_filter
|
323
|
+
else
|
389
324
|
@inspection_filter ||= begin
|
390
325
|
mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
|
391
326
|
ActiveSupport::ParameterFilter.new(@filter_attributes, mask: mask)
|
392
327
|
end
|
393
|
-
else
|
394
|
-
superclass.inspection_filter
|
395
328
|
end
|
396
329
|
end
|
397
330
|
|
@@ -411,12 +344,7 @@ module ActiveRecord
|
|
411
344
|
end
|
412
345
|
end
|
413
346
|
|
414
|
-
#
|
415
|
-
def ===(object) # :nodoc:
|
416
|
-
object.is_a?(self)
|
417
|
-
end
|
418
|
-
|
419
|
-
# Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
|
347
|
+
# Returns an instance of +Arel::Table+ loaded with the current table name.
|
420
348
|
def arel_table # :nodoc:
|
421
349
|
@arel_table ||= Arel::Table.new(table_name, klass: self)
|
422
350
|
end
|
@@ -435,6 +363,28 @@ module ActiveRecord
|
|
435
363
|
end
|
436
364
|
|
437
365
|
private
|
366
|
+
def inherited(subclass)
|
367
|
+
super
|
368
|
+
|
369
|
+
# initialize cache at class definition for thread safety
|
370
|
+
subclass.initialize_find_by_cache
|
371
|
+
unless subclass.base_class?
|
372
|
+
klass = self
|
373
|
+
until klass.base_class?
|
374
|
+
klass.initialize_find_by_cache
|
375
|
+
klass = klass.superclass
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
subclass.class_eval do
|
380
|
+
@arel_table = nil
|
381
|
+
@predicate_builder = nil
|
382
|
+
@inspection_filter = nil
|
383
|
+
@filter_attributes = nil
|
384
|
+
@generated_association_methods = nil
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
438
388
|
def relation
|
439
389
|
relation = Relation.create(self)
|
440
390
|
|
@@ -448,6 +398,19 @@ module ActiveRecord
|
|
448
398
|
def table_metadata
|
449
399
|
TableMetadata.new(self, arel_table)
|
450
400
|
end
|
401
|
+
|
402
|
+
def cached_find_by(keys, values)
|
403
|
+
statement = cached_find_by_statement(keys) { |params|
|
404
|
+
wheres = keys.index_with { params.bind }
|
405
|
+
where(wheres).limit(1)
|
406
|
+
}
|
407
|
+
|
408
|
+
begin
|
409
|
+
statement.execute(values, connection).first
|
410
|
+
rescue TypeError
|
411
|
+
raise ActiveRecord::StatementInvalid
|
412
|
+
end
|
413
|
+
end
|
451
414
|
end
|
452
415
|
|
453
416
|
# New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
|
@@ -455,7 +418,7 @@ module ActiveRecord
|
|
455
418
|
# In both instances, valid attribute keys are determined by the column names of the associated table --
|
456
419
|
# hence you can't have attributes that aren't part of the table columns.
|
457
420
|
#
|
458
|
-
# ==== Example
|
421
|
+
# ==== Example
|
459
422
|
# # Instantiates a single new object
|
460
423
|
# User.new(first_name: 'Jamie')
|
461
424
|
def initialize(attributes = nil)
|
@@ -533,12 +496,17 @@ module ActiveRecord
|
|
533
496
|
# only, not its associations. The extent of a "deep" copy is application
|
534
497
|
# specific and is therefore left to the application to implement according
|
535
498
|
# to its need.
|
536
|
-
# The dup method does not preserve the timestamps (created|updated)_(at|on)
|
499
|
+
# The dup method does not preserve the timestamps (created|updated)_(at|on)
|
500
|
+
# and locking column.
|
537
501
|
|
538
502
|
##
|
539
503
|
def initialize_dup(other) # :nodoc:
|
540
504
|
@attributes = @attributes.deep_dup
|
541
|
-
|
505
|
+
if self.class.composite_primary_key?
|
506
|
+
@primary_key.each { |key| @attributes.reset(key) }
|
507
|
+
else
|
508
|
+
@attributes.reset(@primary_key)
|
509
|
+
end
|
542
510
|
|
543
511
|
_run_initialize_callbacks
|
544
512
|
|
@@ -568,6 +536,27 @@ module ActiveRecord
|
|
568
536
|
coder["active_record_yaml_version"] = 2
|
569
537
|
end
|
570
538
|
|
539
|
+
##
|
540
|
+
# :method: slice
|
541
|
+
#
|
542
|
+
# :call-seq: slice(*methods)
|
543
|
+
#
|
544
|
+
# Returns a hash of the given methods with their names as keys and returned
|
545
|
+
# values as values.
|
546
|
+
#
|
547
|
+
#--
|
548
|
+
# Implemented by ActiveModel::Access#slice.
|
549
|
+
|
550
|
+
##
|
551
|
+
# :method: values_at
|
552
|
+
#
|
553
|
+
# :call-seq: values_at(*methods)
|
554
|
+
#
|
555
|
+
# Returns an array of the values returned by the given methods.
|
556
|
+
#
|
557
|
+
#--
|
558
|
+
# Implemented by ActiveModel::Access#values_at.
|
559
|
+
|
571
560
|
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
572
561
|
# is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
|
573
562
|
#
|
@@ -580,7 +569,7 @@ module ActiveRecord
|
|
580
569
|
def ==(comparison_object)
|
581
570
|
super ||
|
582
571
|
comparison_object.instance_of?(self.class) &&
|
583
|
-
|
572
|
+
primary_key_values_present? &&
|
584
573
|
comparison_object.id == id
|
585
574
|
end
|
586
575
|
alias :eql? :==
|
@@ -590,7 +579,7 @@ module ActiveRecord
|
|
590
579
|
def hash
|
591
580
|
id = self.id
|
592
581
|
|
593
|
-
if
|
582
|
+
if primary_key_values_present?
|
594
583
|
self.class.hash ^ id.hash
|
595
584
|
else
|
596
585
|
super
|
@@ -642,25 +631,33 @@ module ActiveRecord
|
|
642
631
|
#
|
643
632
|
# user = User.first
|
644
633
|
# user.strict_loading! # => true
|
645
|
-
# user.
|
634
|
+
# user.address.city
|
635
|
+
# => ActiveRecord::StrictLoadingViolationError
|
636
|
+
# user.comments.to_a
|
646
637
|
# => ActiveRecord::StrictLoadingViolationError
|
647
638
|
#
|
648
|
-
#
|
639
|
+
# ==== Parameters
|
649
640
|
#
|
650
|
-
# * value - Boolean specifying whether to enable or disable strict loading.
|
651
|
-
# * mode - Symbol specifying strict loading mode. Defaults to :all. Using
|
652
|
-
#
|
653
|
-
#
|
641
|
+
# * +value+ - Boolean specifying whether to enable or disable strict loading.
|
642
|
+
# * <tt>:mode</tt> - Symbol specifying strict loading mode. Defaults to :all. Using
|
643
|
+
# :n_plus_one_only mode will only raise an error if an association that
|
644
|
+
# will lead to an n plus one query is lazily loaded.
|
654
645
|
#
|
655
|
-
#
|
646
|
+
# ==== Examples
|
656
647
|
#
|
657
648
|
# user = User.first
|
658
649
|
# user.strict_loading!(false) # => false
|
659
|
-
# user.
|
660
|
-
# => #<
|
650
|
+
# user.address.city # => "Tatooine"
|
651
|
+
# user.comments.to_a # => [#<Comment:0x00...]
|
652
|
+
#
|
653
|
+
# user.strict_loading!(mode: :n_plus_one_only)
|
654
|
+
# user.address.city # => "Tatooine"
|
655
|
+
# user.comments.to_a # => [#<Comment:0x00...]
|
656
|
+
# user.comments.first.ratings.to_a
|
657
|
+
# => ActiveRecord::StrictLoadingViolationError
|
661
658
|
def strict_loading!(value = true, mode: :all)
|
662
659
|
unless [:all, :n_plus_one_only].include?(mode)
|
663
|
-
raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only]."
|
660
|
+
raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only] but #{mode.inspect} was provided."
|
664
661
|
end
|
665
662
|
|
666
663
|
@strict_loading_mode = mode
|
@@ -688,7 +685,7 @@ module ActiveRecord
|
|
688
685
|
# We check defined?(@attributes) not to issue warnings if the object is
|
689
686
|
# allocated but not initialized.
|
690
687
|
inspection = if defined?(@attributes) && @attributes
|
691
|
-
|
688
|
+
attribute_names.filter_map do |name|
|
692
689
|
if _has_attribute?(name)
|
693
690
|
"#{name}: #{attribute_for_inspect(name)}"
|
694
691
|
end
|
@@ -725,16 +722,6 @@ module ActiveRecord
|
|
725
722
|
end
|
726
723
|
end
|
727
724
|
|
728
|
-
# Returns a hash of the given methods with their names as keys and returned values as values.
|
729
|
-
def slice(*methods)
|
730
|
-
methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
|
731
|
-
end
|
732
|
-
|
733
|
-
# Returns an array of the values returned by the given methods.
|
734
|
-
def values_at(*methods)
|
735
|
-
methods.flatten.map! { |method| public_send(method) }
|
736
|
-
end
|
737
|
-
|
738
725
|
private
|
739
726
|
# +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
|
740
727
|
# the array, and then rescues from the possible +NoMethodError+. If those elements are
|
@@ -763,6 +750,7 @@ module ActiveRecord
|
|
763
750
|
@strict_loading_mode = :all
|
764
751
|
|
765
752
|
klass.define_attribute_methods
|
753
|
+
klass.generate_alias_attributes
|
766
754
|
end
|
767
755
|
|
768
756
|
def initialize_internals_callback
|
@@ -5,6 +5,10 @@ module ActiveRecord
|
|
5
5
|
module CounterCache
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
|
+
included do
|
9
|
+
class_attribute :_counter_cache_columns, instance_accessor: false, default: []
|
10
|
+
end
|
11
|
+
|
8
12
|
module ClassMethods
|
9
13
|
# Resets one or more counter caches to their correct value using an SQL
|
10
14
|
# count query. This is useful when adding new counter caches, or if the
|
@@ -29,6 +33,7 @@ module ActiveRecord
|
|
29
33
|
def reset_counters(id, *counters, touch: nil)
|
30
34
|
object = find(id)
|
31
35
|
|
36
|
+
updates = {}
|
32
37
|
counters.each do |counter_association|
|
33
38
|
has_many_association = _reflect_on_association(counter_association)
|
34
39
|
unless has_many_association
|
@@ -47,19 +52,21 @@ module ActiveRecord
|
|
47
52
|
reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
|
48
53
|
counter_name = reflection.counter_cache_column
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
if
|
53
|
-
|
54
|
-
names = Array.wrap(names)
|
55
|
-
options = names.extract_options!
|
56
|
-
touch_updates = touch_attributes_with_time(*names, **options)
|
57
|
-
updates.merge!(touch_updates)
|
58
|
-
end
|
55
|
+
count_was = object.send(counter_name)
|
56
|
+
count = object.send(counter_association).count(:all)
|
57
|
+
updates[counter_name] = count if count != count_was
|
58
|
+
end
|
59
59
|
|
60
|
-
|
60
|
+
if touch
|
61
|
+
names = touch if touch != true
|
62
|
+
names = Array.wrap(names)
|
63
|
+
options = names.extract_options!
|
64
|
+
touch_updates = touch_attributes_with_time(*names, **options)
|
65
|
+
updates.merge!(touch_updates)
|
61
66
|
end
|
62
67
|
|
68
|
+
unscoped.where(primary_key => object.id).update_all(updates) if updates.any?
|
69
|
+
|
63
70
|
true
|
64
71
|
end
|
65
72
|
|
@@ -80,28 +87,28 @@ module ActiveRecord
|
|
80
87
|
#
|
81
88
|
# ==== Examples
|
82
89
|
#
|
83
|
-
# # For the Post with id of 5, decrement the
|
84
|
-
# # increment the
|
85
|
-
# Post.update_counters 5,
|
90
|
+
# # For the Post with id of 5, decrement the comments_count by 1, and
|
91
|
+
# # increment the actions_count by 1
|
92
|
+
# Post.update_counters 5, comments_count: -1, actions_count: 1
|
86
93
|
# # Executes the following SQL:
|
87
94
|
# # UPDATE posts
|
88
|
-
# # SET
|
89
|
-
# #
|
95
|
+
# # SET comments_count = COALESCE(comments_count, 0) - 1,
|
96
|
+
# # actions_count = COALESCE(actions_count, 0) + 1
|
90
97
|
# # WHERE id = 5
|
91
98
|
#
|
92
|
-
# # For the Posts with id of 10 and 15, increment the
|
93
|
-
# Post.update_counters [10, 15],
|
99
|
+
# # For the Posts with id of 10 and 15, increment the comments_count by 1
|
100
|
+
# Post.update_counters [10, 15], comments_count: 1
|
94
101
|
# # Executes the following SQL:
|
95
102
|
# # UPDATE posts
|
96
|
-
# # SET
|
103
|
+
# # SET comments_count = COALESCE(comments_count, 0) + 1
|
97
104
|
# # WHERE id IN (10, 15)
|
98
105
|
#
|
99
|
-
# # For the Posts with id of 10 and 15, increment the
|
106
|
+
# # For the Posts with id of 10 and 15, increment the comments_count by 1
|
100
107
|
# # and update the updated_at value for each counter.
|
101
|
-
# Post.update_counters [10, 15],
|
108
|
+
# Post.update_counters [10, 15], comments_count: 1, touch: true
|
102
109
|
# # Executes the following SQL:
|
103
110
|
# # UPDATE posts
|
104
|
-
# # SET
|
111
|
+
# # SET comments_count = COALESCE(comments_count, 0) + 1,
|
105
112
|
# # `updated_at` = '2016-10-13T09:59:23-05:00'
|
106
113
|
# # WHERE id IN (10, 15)
|
107
114
|
def update_counters(id, counters)
|
@@ -119,6 +126,7 @@ module ActiveRecord
|
|
119
126
|
#
|
120
127
|
# * +counter_name+ - The name of the field that should be incremented.
|
121
128
|
# * +id+ - The id of the object that should be incremented or an array of ids.
|
129
|
+
# * <tt>:by</tt> - The amount by which to increment the value. Defaults to +1+.
|
122
130
|
# * <tt>:touch</tt> - Touch timestamp columns when updating.
|
123
131
|
# Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
|
124
132
|
# touch that column or an array of symbols to touch just those ones.
|
@@ -129,10 +137,14 @@ module ActiveRecord
|
|
129
137
|
# DiscussionBoard.increment_counter(:posts_count, 5)
|
130
138
|
#
|
131
139
|
# # Increment the posts_count column for the record with an id of 5
|
140
|
+
# # by a specific amount.
|
141
|
+
# DiscussionBoard.increment_counter(:posts_count, 5, by: 3)
|
142
|
+
#
|
143
|
+
# # Increment the posts_count column for the record with an id of 5
|
132
144
|
# # and update the updated_at value.
|
133
145
|
# DiscussionBoard.increment_counter(:posts_count, 5, touch: true)
|
134
|
-
def increment_counter(counter_name, id, touch: nil)
|
135
|
-
update_counters(id, counter_name =>
|
146
|
+
def increment_counter(counter_name, id, by: 1, touch: nil)
|
147
|
+
update_counters(id, counter_name => by, touch: touch)
|
136
148
|
end
|
137
149
|
|
138
150
|
# Decrement a numeric field by one, via a direct SQL update.
|
@@ -144,6 +156,7 @@ module ActiveRecord
|
|
144
156
|
#
|
145
157
|
# * +counter_name+ - The name of the field that should be decremented.
|
146
158
|
# * +id+ - The id of the object that should be decremented or an array of ids.
|
159
|
+
# * <tt>:by</tt> - The amount by which to decrement the value. Defaults to +1+.
|
147
160
|
# * <tt>:touch</tt> - Touch timestamp columns when updating.
|
148
161
|
# Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
|
149
162
|
# touch that column or an array of symbols to touch just those ones.
|
@@ -154,10 +167,18 @@ module ActiveRecord
|
|
154
167
|
# DiscussionBoard.decrement_counter(:posts_count, 5)
|
155
168
|
#
|
156
169
|
# # Decrement the posts_count column for the record with an id of 5
|
170
|
+
# by a specific amount.
|
171
|
+
# DiscussionBoard.decrement_counter(:posts_count, 5, by: 3)
|
172
|
+
#
|
173
|
+
# # Decrement the posts_count column for the record with an id of 5
|
157
174
|
# # and update the updated_at value.
|
158
175
|
# DiscussionBoard.decrement_counter(:posts_count, 5, touch: true)
|
159
|
-
def decrement_counter(counter_name, id, touch: nil)
|
160
|
-
update_counters(id, counter_name => -
|
176
|
+
def decrement_counter(counter_name, id, by: 1, touch: nil)
|
177
|
+
update_counters(id, counter_name => -by, touch: touch)
|
178
|
+
end
|
179
|
+
|
180
|
+
def counter_cache_column?(name) # :nodoc:
|
181
|
+
_counter_cache_columns.include?(name)
|
161
182
|
end
|
162
183
|
end
|
163
184
|
|
@@ -3,13 +3,11 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
class DatabaseConfigurations
|
5
5
|
# ActiveRecord::Base.configurations will return either a HashConfig or
|
6
|
-
# UrlConfig respectively. It will never return a DatabaseConfig object,
|
6
|
+
# UrlConfig respectively. It will never return a +DatabaseConfig+ object,
|
7
7
|
# as this is the parent class for the types of database configuration objects.
|
8
8
|
class DatabaseConfig # :nodoc:
|
9
9
|
attr_reader :env_name, :name
|
10
10
|
|
11
|
-
attr_accessor :owner_name
|
12
|
-
|
13
11
|
def initialize(env_name, name)
|
14
12
|
@env_name = env_name
|
15
13
|
@name = name
|
@@ -19,6 +17,10 @@ module ActiveRecord
|
|
19
17
|
"#{adapter}_connection"
|
20
18
|
end
|
21
19
|
|
20
|
+
def adapter_class_method
|
21
|
+
"#{adapter}_adapter_class"
|
22
|
+
end
|
23
|
+
|
22
24
|
def host
|
23
25
|
raise NotImplementedError
|
24
26
|
end
|
@@ -51,6 +53,10 @@ module ActiveRecord
|
|
51
53
|
raise NotImplementedError
|
52
54
|
end
|
53
55
|
|
56
|
+
def query_cache
|
57
|
+
raise NotImplementedError
|
58
|
+
end
|
59
|
+
|
54
60
|
def checkout_timeout
|
55
61
|
raise NotImplementedError
|
56
62
|
end
|