activerecord 6.1.7 → 7.2.2
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 +616 -1290
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +2 -12
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +60 -21
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +37 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +41 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +4 -4
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +46 -36
- data/lib/active_record/associations/collection_proxy.rb +44 -16
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +29 -19
- data/lib/active_record/associations/has_many_through_association.rb +19 -8
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +212 -53
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -16
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +15 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +429 -522
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +47 -27
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +14 -11
- data/lib/active_record/attribute_methods/serialization.rb +174 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +15 -9
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +164 -52
- data/lib/active_record/attributes.rb +57 -54
- data/lib/active_record/autosave_association.rb +74 -57
- data/lib/active_record/base.rb +27 -5
- data/lib/active_record/callbacks.rb +19 -35
- 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 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +325 -604
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +230 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +378 -143
- data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
- data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +348 -165
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
- data/lib/active_record/connection_adapters/pool_config.rb +26 -16
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +403 -77
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +520 -253
- data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +130 -6
- data/lib/active_record/connection_handling.rb +132 -146
- data/lib/active_record/core.rb +310 -253
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -4
- data/lib/active_record/database_configurations/database_config.rb +34 -10
- data/lib/active_record/database_configurations/hash_config.rb +107 -31
- data/lib/active_record/database_configurations/url_config.rb +38 -13
- data/lib/active_record/database_configurations.rb +96 -60
- data/lib/active_record/delegated_type.rb +90 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +3 -3
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +170 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +170 -62
- data/lib/active_record/errors.rb +210 -27
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- 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 +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +179 -112
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +85 -31
- data/lib/active_record/insert_all.rb +148 -32
- data/lib/active_record/integration.rb +14 -10
- data/lib/active_record/internal_metadata.rb +123 -23
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +43 -27
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +41 -29
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +113 -16
- data/lib/active_record/migration/compatibility.rb +235 -46
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +374 -177
- data/lib/active_record/model_schema.rb +145 -158
- data/lib/active_record/nested_attributes.rb +61 -23
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +282 -283
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +189 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +44 -9
- data/lib/active_record/railtie.rb +229 -71
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +189 -256
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +332 -103
- data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
- data/lib/active_record/relation/batches.rb +200 -65
- data/lib/active_record/relation/calculations.rb +301 -112
- data/lib/active_record/relation/delegation.rb +33 -22
- data/lib/active_record/relation/finder_methods.rb +123 -52
- data/lib/active_record/relation/merger.rb +26 -19
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +29 -22
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +870 -163
- data/lib/active_record/relation/record_fetch_warning.rb +10 -9
- data/lib/active_record/relation/spawn_methods.rb +7 -6
- data/lib/active_record/relation/where_clause.rb +15 -36
- data/lib/active_record/relation.rb +736 -145
- data/lib/active_record/result.rb +67 -54
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +84 -34
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +90 -31
- data/lib/active_record/schema_migration.rb +74 -23
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +6 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +30 -9
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +288 -149
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +173 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +118 -41
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -7
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -7
- 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 +65 -15
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +444 -32
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +7 -2
- data/lib/arel/predications.rb +14 -4
- data/lib/arel/select_manager.rb +11 -5
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +20 -5
- data/lib/arel/visitors/dot.rb +81 -90
- data/lib/arel/visitors/mysql.rb +23 -5
- data/lib/arel/visitors/postgresql.rb +1 -22
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +170 -36
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +23 -4
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- 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
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +103 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
data/lib/active_record/core.rb
CHANGED
@@ -1,42 +1,50 @@
|
|
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
|
##
|
15
16
|
# :singleton-method:
|
16
17
|
#
|
17
|
-
# Accepts a logger conforming to the interface of Log4r
|
18
|
-
# passed on to any new database
|
19
|
-
#
|
20
|
-
|
18
|
+
# Accepts a logger conforming to the interface of Log4r or the default
|
19
|
+
# Ruby +Logger+ class, which is then passed on to any new database
|
20
|
+
# connections made. You can retrieve this logger by calling +logger+ on
|
21
|
+
# either an Active Record model class or an Active Record model instance.
|
22
|
+
class_attribute :logger, instance_writer: false
|
23
|
+
|
24
|
+
class_attribute :_destroy_association_async_job, instance_accessor: false, default: "ActiveRecord::DestroyAssociationAsyncJob"
|
25
|
+
|
26
|
+
# The job class used to destroy associations in the background.
|
27
|
+
def self.destroy_association_async_job
|
28
|
+
if _destroy_association_async_job.is_a?(String)
|
29
|
+
self._destroy_association_async_job = _destroy_association_async_job.constantize
|
30
|
+
end
|
31
|
+
_destroy_association_async_job
|
32
|
+
rescue NameError => error
|
33
|
+
raise NameError, "Unable to load destroy_association_async_job: #{error.message}"
|
34
|
+
end
|
21
35
|
|
22
|
-
|
23
|
-
|
24
|
-
#
|
25
|
-
# Specifies if the methods calling database queries should be logged below
|
26
|
-
# their relevant queries. Defaults to false.
|
27
|
-
mattr_accessor :verbose_query_logs, instance_writer: false, default: false
|
36
|
+
singleton_class.alias_method :destroy_association_async_job=, :_destroy_association_async_job=
|
37
|
+
delegate :destroy_association_async_job, to: :class
|
28
38
|
|
29
39
|
##
|
30
40
|
# :singleton-method:
|
31
41
|
#
|
32
|
-
# Specifies the
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
#
|
37
|
-
|
38
|
-
# Specifies the job used to destroy associations in the background
|
39
|
-
class_attribute :destroy_association_async_job, instance_writer: false, instance_predicate: false, default: false
|
42
|
+
# Specifies the maximum number of records that will be destroyed in a
|
43
|
+
# single background job by the <tt>dependent: :destroy_async</tt>
|
44
|
+
# association option. When +nil+ (default), all dependent records will be
|
45
|
+
# destroyed in a single background job. If specified, the records to be
|
46
|
+
# destroyed will be split into multiple background jobs.
|
47
|
+
class_attribute :destroy_association_async_batch_size, instance_writer: false, instance_predicate: false, default: nil
|
40
48
|
|
41
49
|
##
|
42
50
|
# Contains the database configuration - as is typically stored in config/database.yml -
|
@@ -46,106 +54,45 @@ module ActiveRecord
|
|
46
54
|
#
|
47
55
|
# development:
|
48
56
|
# adapter: sqlite3
|
49
|
-
# database:
|
57
|
+
# database: storage/development.sqlite3
|
50
58
|
#
|
51
59
|
# production:
|
52
60
|
# adapter: sqlite3
|
53
|
-
# database:
|
61
|
+
# database: storage/production.sqlite3
|
54
62
|
#
|
55
63
|
# ...would result in ActiveRecord::Base.configurations to look like this:
|
56
64
|
#
|
57
65
|
# #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
|
58
66
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
|
59
|
-
# @name="primary", @config={adapter: "sqlite3", database: "
|
67
|
+
# @name="primary", @config={adapter: "sqlite3", database: "storage/development.sqlite3"}>,
|
60
68
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
|
61
|
-
# @name="primary", @config={adapter: "sqlite3", database: "
|
69
|
+
# @name="primary", @config={adapter: "sqlite3", database: "storage/production.sqlite3"}>
|
62
70
|
# ]>
|
63
71
|
def self.configurations=(config)
|
64
72
|
@@configurations = ActiveRecord::DatabaseConfigurations.new(config)
|
65
73
|
end
|
66
74
|
self.configurations = {}
|
67
75
|
|
68
|
-
# Returns fully resolved ActiveRecord::DatabaseConfigurations object
|
76
|
+
# Returns a fully resolved ActiveRecord::DatabaseConfigurations object.
|
69
77
|
def self.configurations
|
70
78
|
@@configurations
|
71
79
|
end
|
72
80
|
|
73
81
|
##
|
74
82
|
# :singleton-method:
|
75
|
-
#
|
76
|
-
#
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
# :singleton-method:
|
81
|
-
# Specifies the format to use when dumping the database schema with Rails'
|
82
|
-
# Rakefile. If :sql, the schema is dumped as (potentially database-
|
83
|
-
# specific) SQL statements. If :ruby, the schema is dumped as an
|
84
|
-
# ActiveRecord::Schema file which can be loaded into any database that
|
85
|
-
# supports migrations. Use :ruby if you want to have different database
|
86
|
-
# adapters for, e.g., your development and test environments.
|
87
|
-
mattr_accessor :schema_format, instance_writer: false, default: :ruby
|
88
|
-
|
89
|
-
##
|
90
|
-
# :singleton-method:
|
91
|
-
# Specifies if an error should be raised if the query has an order being
|
92
|
-
# ignored when doing batch queries. Useful in applications where the
|
93
|
-
# scope being ignored is error-worthy, rather than a warning.
|
94
|
-
mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
|
95
|
-
|
96
|
-
##
|
97
|
-
# :singleton-method:
|
98
|
-
# Specify whether or not to use timestamps for migration versions
|
99
|
-
mattr_accessor :timestamped_migrations, instance_writer: false, default: true
|
100
|
-
|
101
|
-
##
|
102
|
-
# :singleton-method:
|
103
|
-
# Specify whether schema dump should happen at the end of the
|
104
|
-
# db:migrate rails command. This is true by default, which is useful for the
|
105
|
-
# development environment. This should ideally be false in the production
|
106
|
-
# environment where dumping schema is rarely needed.
|
107
|
-
mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
|
108
|
-
|
109
|
-
##
|
110
|
-
# :singleton-method:
|
111
|
-
# Specifies which database schemas to dump when calling db:schema:dump.
|
112
|
-
# If the value is :schema_search_path (the default), any schemas listed in
|
113
|
-
# schema_search_path are dumped. Use :all to dump all schemas regardless
|
114
|
-
# of schema_search_path, or a string of comma separated schemas for a
|
115
|
-
# custom list.
|
116
|
-
mattr_accessor :dump_schemas, instance_writer: false, default: :schema_search_path
|
117
|
-
|
118
|
-
##
|
119
|
-
# :singleton-method:
|
120
|
-
# Specify a threshold for the size of query result sets. If the number of
|
121
|
-
# records in the set exceeds the threshold, a warning is logged. This can
|
122
|
-
# be used to identify queries which load thousands of records and
|
123
|
-
# potentially cause memory bloat.
|
124
|
-
mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
|
125
|
-
|
126
|
-
##
|
127
|
-
# :singleton-method:
|
128
|
-
# Show a warning when Rails couldn't parse your database.yml
|
129
|
-
# for multiple databases.
|
130
|
-
mattr_accessor :suppress_multiple_database_warning, instance_writer: false, default: false
|
131
|
-
|
132
|
-
mattr_accessor :maintain_test_schema, instance_accessor: false
|
83
|
+
# Force enumeration of all columns in SELECT statements.
|
84
|
+
# e.g. <tt>SELECT first_name, last_name FROM ...</tt> instead of <tt>SELECT * FROM ...</tt>
|
85
|
+
# This avoids +PreparedStatementCacheExpired+ errors when a column is added
|
86
|
+
# to the database while the app is running.
|
87
|
+
class_attribute :enumerate_columns_in_select_statements, instance_accessor: false, default: false
|
133
88
|
|
134
89
|
class_attribute :belongs_to_required_by_default, instance_accessor: false
|
135
90
|
|
136
|
-
##
|
137
|
-
# :singleton-method:
|
138
|
-
# Set the application to log or raise when an association violates strict loading.
|
139
|
-
# Defaults to :raise.
|
140
|
-
mattr_accessor :action_on_strict_loading_violation, instance_accessor: false, default: :raise
|
141
|
-
|
142
91
|
class_attribute :strict_loading_by_default, instance_accessor: false, default: false
|
143
92
|
|
144
|
-
|
93
|
+
class_attribute :has_many_inversing, instance_accessor: false, default: false
|
145
94
|
|
146
|
-
|
147
|
-
|
148
|
-
mattr_accessor :has_many_inversing, instance_accessor: false, default: false
|
95
|
+
class_attribute :run_commit_callbacks_on_first_saved_instances_in_transaction, instance_accessor: false, default: true
|
149
96
|
|
150
97
|
class_attribute :default_connection_handler, instance_writer: false
|
151
98
|
|
@@ -153,40 +100,50 @@ module ActiveRecord
|
|
153
100
|
|
154
101
|
class_attribute :default_shard, instance_writer: false
|
155
102
|
|
156
|
-
|
103
|
+
class_attribute :shard_selector, instance_accessor: false, default: nil
|
157
104
|
|
158
|
-
|
159
|
-
#
|
160
|
-
|
105
|
+
##
|
106
|
+
# :singleton-method:
|
107
|
+
#
|
108
|
+
# Specifies the attributes that will be included in the output of the
|
109
|
+
# #inspect method:
|
110
|
+
#
|
111
|
+
# Post.attributes_for_inspect = [:id, :title]
|
112
|
+
# Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!">"
|
113
|
+
#
|
114
|
+
# When set to `:all` inspect will list all the record's attributes:
|
115
|
+
#
|
116
|
+
# Post.attributes_for_inspect = :all
|
117
|
+
# Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
118
|
+
class_attribute :attributes_for_inspect, instance_accessor: false, default: :all
|
161
119
|
|
162
|
-
|
163
|
-
|
164
|
-
|
120
|
+
def self.application_record_class? # :nodoc:
|
121
|
+
if ActiveRecord.application_record_class
|
122
|
+
self == ActiveRecord.application_record_class
|
123
|
+
else
|
124
|
+
if defined?(ApplicationRecord) && self == ApplicationRecord
|
125
|
+
true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
165
129
|
|
166
130
|
self.filter_attributes = []
|
167
131
|
|
168
132
|
def self.connection_handler
|
169
|
-
|
133
|
+
ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] || default_connection_handler
|
170
134
|
end
|
171
135
|
|
172
136
|
def self.connection_handler=(handler)
|
173
|
-
|
137
|
+
ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] = handler
|
174
138
|
end
|
175
139
|
|
176
|
-
def self.
|
177
|
-
|
178
|
-
raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
|
179
|
-
end
|
180
|
-
|
181
|
-
@@connection_handlers ||= {}
|
140
|
+
def self.asynchronous_queries_session # :nodoc:
|
141
|
+
asynchronous_queries_tracker.current_session
|
182
142
|
end
|
183
143
|
|
184
|
-
def self.
|
185
|
-
|
186
|
-
|
187
|
-
end
|
188
|
-
|
189
|
-
@@connection_handlers = handlers
|
144
|
+
def self.asynchronous_queries_tracker # :nodoc:
|
145
|
+
ActiveSupport::IsolatedExecutionState[:active_record_asynchronous_queries_tracker] ||= \
|
146
|
+
AsynchronousQueriesTracker.new
|
190
147
|
end
|
191
148
|
|
192
149
|
# Returns the symbol representing the current connected role.
|
@@ -199,16 +156,12 @@ module ActiveRecord
|
|
199
156
|
# ActiveRecord::Base.current_role #=> :reading
|
200
157
|
# end
|
201
158
|
def self.current_role
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
connected_to_stack.reverse_each do |hash|
|
206
|
-
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
|
207
|
-
return hash[:role] if hash[:role] && hash[:klasses].include?(connection_classes)
|
208
|
-
end
|
209
|
-
|
210
|
-
default_role
|
159
|
+
connected_to_stack.reverse_each do |hash|
|
160
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
|
161
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
|
211
162
|
end
|
163
|
+
|
164
|
+
default_role
|
212
165
|
end
|
213
166
|
|
214
167
|
# Returns the symbol representing the current connected shard.
|
@@ -223,7 +176,7 @@ module ActiveRecord
|
|
223
176
|
def self.current_shard
|
224
177
|
connected_to_stack.reverse_each do |hash|
|
225
178
|
return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
|
226
|
-
return hash[:shard] if hash[:shard] && hash[:klasses].include?(
|
179
|
+
return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_class_for_self)
|
227
180
|
end
|
228
181
|
|
229
182
|
default_shard
|
@@ -240,24 +193,20 @@ module ActiveRecord
|
|
240
193
|
# ActiveRecord::Base.current_preventing_writes #=> false
|
241
194
|
# end
|
242
195
|
def self.current_preventing_writes
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
connected_to_stack.reverse_each do |hash|
|
247
|
-
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
|
248
|
-
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_classes)
|
249
|
-
end
|
250
|
-
|
251
|
-
false
|
196
|
+
connected_to_stack.reverse_each do |hash|
|
197
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
|
198
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
|
252
199
|
end
|
200
|
+
|
201
|
+
false
|
253
202
|
end
|
254
203
|
|
255
204
|
def self.connected_to_stack # :nodoc:
|
256
|
-
if connected_to_stack =
|
205
|
+
if connected_to_stack = ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack]
|
257
206
|
connected_to_stack
|
258
207
|
else
|
259
208
|
connected_to_stack = Concurrent::Array.new
|
260
|
-
|
209
|
+
ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack] = connected_to_stack
|
261
210
|
connected_to_stack
|
262
211
|
end
|
263
212
|
end
|
@@ -266,7 +215,7 @@ module ActiveRecord
|
|
266
215
|
@connection_class = b
|
267
216
|
end
|
268
217
|
|
269
|
-
def self.connection_class # :nodoc
|
218
|
+
def self.connection_class # :nodoc:
|
270
219
|
@connection_class ||= false
|
271
220
|
end
|
272
221
|
|
@@ -274,7 +223,7 @@ module ActiveRecord
|
|
274
223
|
self.connection_class
|
275
224
|
end
|
276
225
|
|
277
|
-
def self.
|
226
|
+
def self.connection_class_for_self # :nodoc:
|
278
227
|
klass = self
|
279
228
|
|
280
229
|
until klass == Base
|
@@ -285,22 +234,14 @@ module ActiveRecord
|
|
285
234
|
klass
|
286
235
|
end
|
287
236
|
|
288
|
-
def self.allow_unsafe_raw_sql # :nodoc:
|
289
|
-
ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql is deprecated and will be removed in Rails 7.0")
|
290
|
-
end
|
291
|
-
|
292
|
-
def self.allow_unsafe_raw_sql=(value) # :nodoc:
|
293
|
-
ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql= is deprecated and will be removed in Rails 7.0")
|
294
|
-
end
|
295
|
-
|
296
237
|
self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
|
297
|
-
self.default_role = writing_role
|
238
|
+
self.default_role = ActiveRecord.writing_role
|
298
239
|
self.default_shard = :default
|
299
240
|
|
300
241
|
def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
|
301
|
-
case action_on_strict_loading_violation
|
242
|
+
case ActiveRecord.action_on_strict_loading_violation
|
302
243
|
when :raise
|
303
|
-
message =
|
244
|
+
message = reflection.strict_loading_violation_message(owner)
|
304
245
|
raise ActiveRecord::StrictLoadingViolationError.new(message)
|
305
246
|
when :log
|
306
247
|
name = "strict_loading_violation.active_record"
|
@@ -314,19 +255,6 @@ module ActiveRecord
|
|
314
255
|
@find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
|
315
256
|
end
|
316
257
|
|
317
|
-
def inherited(child_class) # :nodoc:
|
318
|
-
# initialize cache at class definition for thread safety
|
319
|
-
child_class.initialize_find_by_cache
|
320
|
-
unless child_class.base_class?
|
321
|
-
klass = self
|
322
|
-
until klass.base_class?
|
323
|
-
klass.initialize_find_by_cache
|
324
|
-
klass = klass.superclass
|
325
|
-
end
|
326
|
-
end
|
327
|
-
super
|
328
|
-
end
|
329
|
-
|
330
258
|
def find(*ids) # :nodoc:
|
331
259
|
# We don't have cache keys for this stuff yet
|
332
260
|
return super unless ids.length == 1
|
@@ -336,14 +264,8 @@ module ActiveRecord
|
|
336
264
|
|
337
265
|
return super if StatementCache.unsupported_value?(id)
|
338
266
|
|
339
|
-
|
340
|
-
|
341
|
-
statement = cached_find_by_statement(key) { |params|
|
342
|
-
where(key => params.bind).limit(1)
|
343
|
-
}
|
344
|
-
|
345
|
-
statement.execute([id], connection).first ||
|
346
|
-
raise(RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id))
|
267
|
+
cached_find_by([primary_key], [id]) ||
|
268
|
+
raise(RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}", name, primary_key, id))
|
347
269
|
end
|
348
270
|
|
349
271
|
def find_by(*args) # :nodoc:
|
@@ -365,31 +287,36 @@ module ActiveRecord
|
|
365
287
|
elsif reflection.belongs_to? && !reflection.polymorphic?
|
366
288
|
key = reflection.join_foreign_key
|
367
289
|
pkey = reflection.join_primary_key
|
368
|
-
|
290
|
+
|
291
|
+
if pkey.is_a?(Array)
|
292
|
+
if pkey.all? { |attribute| value.respond_to?(attribute) }
|
293
|
+
value = pkey.map do |attribute|
|
294
|
+
if attribute == "id"
|
295
|
+
value.id_value
|
296
|
+
else
|
297
|
+
value.public_send(attribute)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
composite_primary_key = true
|
301
|
+
end
|
302
|
+
else
|
303
|
+
value = value.public_send(pkey) if value.respond_to?(pkey)
|
304
|
+
end
|
369
305
|
end
|
370
306
|
|
371
|
-
if !
|
307
|
+
if !composite_primary_key &&
|
308
|
+
(!columns_hash.key?(key) || StatementCache.unsupported_value?(value))
|
372
309
|
return super
|
373
310
|
end
|
374
311
|
|
375
312
|
h[key] = value
|
376
313
|
end
|
377
314
|
|
378
|
-
keys
|
379
|
-
statement = cached_find_by_statement(keys) { |params|
|
380
|
-
wheres = keys.index_with { params.bind }
|
381
|
-
where(wheres).limit(1)
|
382
|
-
}
|
383
|
-
|
384
|
-
begin
|
385
|
-
statement.execute(hash.values, connection).first
|
386
|
-
rescue TypeError
|
387
|
-
raise ActiveRecord::StatementInvalid
|
388
|
-
end
|
315
|
+
cached_find_by(hash.keys, hash.values)
|
389
316
|
end
|
390
317
|
|
391
318
|
def find_by!(*args) # :nodoc:
|
392
|
-
find_by(*args) ||
|
319
|
+
find_by(*args) || where(*args).raise_record_not_found_exception!
|
393
320
|
end
|
394
321
|
|
395
322
|
def initialize_generated_modules # :nodoc:
|
@@ -408,10 +335,10 @@ module ActiveRecord
|
|
408
335
|
|
409
336
|
# Returns columns which shouldn't be exposed while calling +#inspect+.
|
410
337
|
def filter_attributes
|
411
|
-
if
|
412
|
-
@filter_attributes
|
413
|
-
else
|
338
|
+
if @filter_attributes.nil?
|
414
339
|
superclass.filter_attributes
|
340
|
+
else
|
341
|
+
@filter_attributes
|
415
342
|
end
|
416
343
|
end
|
417
344
|
|
@@ -422,24 +349,24 @@ module ActiveRecord
|
|
422
349
|
end
|
423
350
|
|
424
351
|
def inspection_filter # :nodoc:
|
425
|
-
if
|
352
|
+
if @filter_attributes.nil?
|
353
|
+
superclass.inspection_filter
|
354
|
+
else
|
426
355
|
@inspection_filter ||= begin
|
427
356
|
mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
|
428
357
|
ActiveSupport::ParameterFilter.new(@filter_attributes, mask: mask)
|
429
358
|
end
|
430
|
-
else
|
431
|
-
superclass.inspection_filter
|
432
359
|
end
|
433
360
|
end
|
434
361
|
|
435
362
|
# Returns a string like 'Post(id:integer, title:string, body:text)'
|
436
363
|
def inspect # :nodoc:
|
437
|
-
if self == Base
|
364
|
+
if self == Base || singleton_class?
|
438
365
|
super
|
439
366
|
elsif abstract_class?
|
440
367
|
"#{super}(abstract)"
|
441
|
-
elsif !connected?
|
442
|
-
"#{super} (call '#{super}.
|
368
|
+
elsif !schema_loaded? && !connected?
|
369
|
+
"#{super} (call '#{super}.load_schema' to load schema informations)"
|
443
370
|
elsif table_exists?
|
444
371
|
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
|
445
372
|
"#{super}(#{attr_list})"
|
@@ -448,25 +375,11 @@ module ActiveRecord
|
|
448
375
|
end
|
449
376
|
end
|
450
377
|
|
451
|
-
#
|
452
|
-
def ===(object) # :nodoc:
|
453
|
-
object.is_a?(self)
|
454
|
-
end
|
455
|
-
|
456
|
-
# Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
|
457
|
-
#
|
458
|
-
# class Post < ActiveRecord::Base
|
459
|
-
# scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
|
460
|
-
# end
|
378
|
+
# Returns an instance of +Arel::Table+ loaded with the current table name.
|
461
379
|
def arel_table # :nodoc:
|
462
380
|
@arel_table ||= Arel::Table.new(table_name, klass: self)
|
463
381
|
end
|
464
382
|
|
465
|
-
def arel_attribute(name, table = arel_table) # :nodoc:
|
466
|
-
table[name]
|
467
|
-
end
|
468
|
-
deprecate :arel_attribute
|
469
|
-
|
470
383
|
def predicate_builder # :nodoc:
|
471
384
|
@predicate_builder ||= PredicateBuilder.new(table_metadata)
|
472
385
|
end
|
@@ -475,16 +388,34 @@ module ActiveRecord
|
|
475
388
|
TypeCaster::Map.new(self)
|
476
389
|
end
|
477
390
|
|
478
|
-
def
|
479
|
-
false
|
480
|
-
end
|
481
|
-
|
482
|
-
def cached_find_by_statement(key, &block) # :nodoc:
|
391
|
+
def cached_find_by_statement(connection, key, &block) # :nodoc:
|
483
392
|
cache = @find_by_statement_cache[connection.prepared_statements]
|
484
393
|
cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
|
485
394
|
end
|
486
395
|
|
487
396
|
private
|
397
|
+
def inherited(subclass)
|
398
|
+
super
|
399
|
+
|
400
|
+
# initialize cache at class definition for thread safety
|
401
|
+
subclass.initialize_find_by_cache
|
402
|
+
unless subclass.base_class?
|
403
|
+
klass = self
|
404
|
+
until klass.base_class?
|
405
|
+
klass.initialize_find_by_cache
|
406
|
+
klass = klass.superclass
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
subclass.class_eval do
|
411
|
+
@arel_table = nil
|
412
|
+
@predicate_builder = nil
|
413
|
+
@inspection_filter = nil
|
414
|
+
@filter_attributes ||= nil
|
415
|
+
@generated_association_methods ||= nil
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
488
419
|
def relation
|
489
420
|
relation = Relation.create(self)
|
490
421
|
|
@@ -498,6 +429,27 @@ module ActiveRecord
|
|
498
429
|
def table_metadata
|
499
430
|
TableMetadata.new(self, arel_table)
|
500
431
|
end
|
432
|
+
|
433
|
+
def cached_find_by(keys, values)
|
434
|
+
with_connection do |connection|
|
435
|
+
statement = cached_find_by_statement(connection, keys) { |params|
|
436
|
+
wheres = keys.index_with do |key|
|
437
|
+
if key.is_a?(Array)
|
438
|
+
[key.map { params.bind }]
|
439
|
+
else
|
440
|
+
params.bind
|
441
|
+
end
|
442
|
+
end
|
443
|
+
where(wheres).limit(1)
|
444
|
+
}
|
445
|
+
|
446
|
+
begin
|
447
|
+
statement.execute(values.flatten, connection, allow_retry: true).first
|
448
|
+
rescue TypeError
|
449
|
+
raise ActiveRecord::StatementInvalid
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
501
453
|
end
|
502
454
|
|
503
455
|
# New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
|
@@ -505,7 +457,7 @@ module ActiveRecord
|
|
505
457
|
# In both instances, valid attribute keys are determined by the column names of the associated table --
|
506
458
|
# hence you can't have attributes that aren't part of the table columns.
|
507
459
|
#
|
508
|
-
# ==== Example
|
460
|
+
# ==== Example
|
509
461
|
# # Instantiates a single new object
|
510
462
|
# User.new(first_name: 'Jamie')
|
511
463
|
def initialize(attributes = nil)
|
@@ -515,7 +467,7 @@ module ActiveRecord
|
|
515
467
|
init_internals
|
516
468
|
initialize_internals_callback
|
517
469
|
|
518
|
-
|
470
|
+
super
|
519
471
|
|
520
472
|
yield self if block_given?
|
521
473
|
_run_initialize_callbacks
|
@@ -536,7 +488,7 @@ module ActiveRecord
|
|
536
488
|
# post.init_with(coder)
|
537
489
|
# post.title # => 'hello world'
|
538
490
|
def init_with(coder, &block)
|
539
|
-
coder = LegacyYamlAdapter.convert(
|
491
|
+
coder = LegacyYamlAdapter.convert(coder)
|
540
492
|
attributes = self.class.yaml_encoder.decode(coder)
|
541
493
|
init_with_attributes(attributes, coder["new_record"], &block)
|
542
494
|
end
|
@@ -583,12 +535,17 @@ module ActiveRecord
|
|
583
535
|
# only, not its associations. The extent of a "deep" copy is application
|
584
536
|
# specific and is therefore left to the application to implement according
|
585
537
|
# to its need.
|
586
|
-
# The dup method does not preserve the timestamps (created|updated)_(at|on)
|
538
|
+
# The dup method does not preserve the timestamps (created|updated)_(at|on)
|
539
|
+
# and locking column.
|
587
540
|
|
588
541
|
##
|
589
542
|
def initialize_dup(other) # :nodoc:
|
590
543
|
@attributes = @attributes.deep_dup
|
591
|
-
|
544
|
+
if self.class.composite_primary_key?
|
545
|
+
@primary_key.each { |key| @attributes.reset(key) }
|
546
|
+
else
|
547
|
+
@attributes.reset(@primary_key)
|
548
|
+
end
|
592
549
|
|
593
550
|
_run_initialize_callbacks
|
594
551
|
|
@@ -618,6 +575,35 @@ module ActiveRecord
|
|
618
575
|
coder["active_record_yaml_version"] = 2
|
619
576
|
end
|
620
577
|
|
578
|
+
##
|
579
|
+
# :method: slice
|
580
|
+
#
|
581
|
+
# :call-seq: slice(*methods)
|
582
|
+
#
|
583
|
+
# Returns a hash of the given methods with their names as keys and returned
|
584
|
+
# values as values.
|
585
|
+
#
|
586
|
+
# topic = Topic.new(title: "Budget", author_name: "Jason")
|
587
|
+
# topic.slice(:title, :author_name)
|
588
|
+
# => { "title" => "Budget", "author_name" => "Jason" }
|
589
|
+
#
|
590
|
+
#--
|
591
|
+
# Implemented by ActiveModel::Access#slice.
|
592
|
+
|
593
|
+
##
|
594
|
+
# :method: values_at
|
595
|
+
#
|
596
|
+
# :call-seq: values_at(*methods)
|
597
|
+
#
|
598
|
+
# Returns an array of the values returned by the given methods.
|
599
|
+
#
|
600
|
+
# topic = Topic.new(title: "Budget", author_name: "Jason")
|
601
|
+
# topic.values_at(:title, :author_name)
|
602
|
+
# => ["Budget", "Jason"]
|
603
|
+
#
|
604
|
+
#--
|
605
|
+
# Implemented by ActiveModel::Access#values_at.
|
606
|
+
|
621
607
|
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
622
608
|
# is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
|
623
609
|
#
|
@@ -630,7 +616,7 @@ module ActiveRecord
|
|
630
616
|
def ==(comparison_object)
|
631
617
|
super ||
|
632
618
|
comparison_object.instance_of?(self.class) &&
|
633
|
-
|
619
|
+
primary_key_values_present? &&
|
634
620
|
comparison_object.id == id
|
635
621
|
end
|
636
622
|
alias :eql? :==
|
@@ -638,7 +624,9 @@ module ActiveRecord
|
|
638
624
|
# Delegates to id in order to allow two records of the same type and id to work with something like:
|
639
625
|
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
|
640
626
|
def hash
|
641
|
-
|
627
|
+
id = self.id
|
628
|
+
|
629
|
+
if primary_key_values_present?
|
642
630
|
self.class.hash ^ id.hash
|
643
631
|
else
|
644
632
|
super
|
@@ -689,14 +677,57 @@ module ActiveRecord
|
|
689
677
|
# if the record tries to lazily load an association.
|
690
678
|
#
|
691
679
|
# user = User.first
|
692
|
-
# user.strict_loading!
|
680
|
+
# user.strict_loading! # => true
|
681
|
+
# user.address.city
|
682
|
+
# => ActiveRecord::StrictLoadingViolationError
|
693
683
|
# user.comments.to_a
|
694
684
|
# => ActiveRecord::StrictLoadingViolationError
|
695
|
-
|
696
|
-
|
685
|
+
#
|
686
|
+
# ==== Parameters
|
687
|
+
#
|
688
|
+
# * +value+ - Boolean specifying whether to enable or disable strict loading.
|
689
|
+
# * <tt>:mode</tt> - Symbol specifying strict loading mode. Defaults to :all. Using
|
690
|
+
# :n_plus_one_only mode will only raise an error if an association that
|
691
|
+
# will lead to an n plus one query is lazily loaded.
|
692
|
+
#
|
693
|
+
# ==== Examples
|
694
|
+
#
|
695
|
+
# user = User.first
|
696
|
+
# user.strict_loading!(false) # => false
|
697
|
+
# user.address.city # => "Tatooine"
|
698
|
+
# user.comments.to_a # => [#<Comment:0x00...]
|
699
|
+
#
|
700
|
+
# user.strict_loading!(mode: :n_plus_one_only)
|
701
|
+
# user.address.city # => "Tatooine"
|
702
|
+
# user.comments.to_a # => [#<Comment:0x00...]
|
703
|
+
# user.comments.first.ratings.to_a
|
704
|
+
# => ActiveRecord::StrictLoadingViolationError
|
705
|
+
def strict_loading!(value = true, mode: :all)
|
706
|
+
unless [:all, :n_plus_one_only].include?(mode)
|
707
|
+
raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only] but #{mode.inspect} was provided."
|
708
|
+
end
|
709
|
+
|
710
|
+
@strict_loading_mode = mode
|
711
|
+
@strict_loading = value
|
712
|
+
end
|
713
|
+
|
714
|
+
attr_reader :strict_loading_mode
|
715
|
+
|
716
|
+
# Returns +true+ if the record uses strict_loading with +:n_plus_one_only+ mode enabled.
|
717
|
+
def strict_loading_n_plus_one_only?
|
718
|
+
@strict_loading_mode == :n_plus_one_only
|
719
|
+
end
|
720
|
+
|
721
|
+
# Returns +true+ if the record uses strict_loading with +:all+ mode enabled.
|
722
|
+
def strict_loading_all?
|
723
|
+
@strict_loading_mode == :all
|
697
724
|
end
|
698
725
|
|
699
726
|
# Marks this record as read only.
|
727
|
+
#
|
728
|
+
# customer = Customer.first
|
729
|
+
# customer.readonly!
|
730
|
+
# customer.save # Raises an ActiveRecord::ReadOnlyRecord
|
700
731
|
def readonly!
|
701
732
|
@readonly = true
|
702
733
|
end
|
@@ -705,21 +736,28 @@ module ActiveRecord
|
|
705
736
|
self.class.connection_handler
|
706
737
|
end
|
707
738
|
|
708
|
-
# Returns the
|
739
|
+
# Returns the attributes of the record as a nicely formatted string.
|
740
|
+
#
|
741
|
+
# Post.first.inspect
|
742
|
+
# #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
743
|
+
#
|
744
|
+
# The attributes can be limited by setting <tt>.attributes_for_inspect</tt>.
|
745
|
+
#
|
746
|
+
# Post.attributes_for_inspect = [:id, :title]
|
747
|
+
# Post.first.inspect
|
748
|
+
# #=> "#<Post id: 1, title: "Hello, World!">"
|
709
749
|
def inspect
|
710
|
-
|
711
|
-
|
712
|
-
inspection = if defined?(@attributes) && @attributes
|
713
|
-
self.class.attribute_names.collect do |name|
|
714
|
-
if _has_attribute?(name)
|
715
|
-
"#{name}: #{attribute_for_inspect(name)}"
|
716
|
-
end
|
717
|
-
end.compact.join(", ")
|
718
|
-
else
|
719
|
-
"not initialized"
|
720
|
-
end
|
750
|
+
inspect_with_attributes(attributes_for_inspect)
|
751
|
+
end
|
721
752
|
|
722
|
-
|
753
|
+
# Returns all attributes of the record as a nicely formatted string,
|
754
|
+
# ignoring <tt>.attributes_for_inspect</tt>.
|
755
|
+
#
|
756
|
+
# Post.first.full_inspect
|
757
|
+
# #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
758
|
+
#
|
759
|
+
def full_inspect
|
760
|
+
inspect_with_attributes(all_attributes_for_inspect)
|
723
761
|
end
|
724
762
|
|
725
763
|
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
|
@@ -727,17 +765,17 @@ module ActiveRecord
|
|
727
765
|
def pretty_print(pp)
|
728
766
|
return super if custom_inspect_method_defined?
|
729
767
|
pp.object_address_group(self) do
|
730
|
-
if
|
731
|
-
attr_names =
|
768
|
+
if @attributes
|
769
|
+
attr_names = attributes_for_inspect.select { |name| _has_attribute?(name.to_s) }
|
732
770
|
pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
|
771
|
+
attr_name = attr_name.to_s
|
733
772
|
pp.breakable " "
|
734
773
|
pp.group(1) do
|
735
774
|
pp.text attr_name
|
736
775
|
pp.text ":"
|
737
776
|
pp.breakable
|
738
|
-
value =
|
739
|
-
|
740
|
-
pp.pp value
|
777
|
+
value = attribute_for_inspect(attr_name)
|
778
|
+
pp.text value
|
741
779
|
end
|
742
780
|
end
|
743
781
|
else
|
@@ -747,16 +785,6 @@ module ActiveRecord
|
|
747
785
|
end
|
748
786
|
end
|
749
787
|
|
750
|
-
# Returns a hash of the given methods with their names as keys and returned values as values.
|
751
|
-
def slice(*methods)
|
752
|
-
methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
|
753
|
-
end
|
754
|
-
|
755
|
-
# Returns an array of the values returned by the given methods.
|
756
|
-
def values_at(*methods)
|
757
|
-
methods.flatten.map! { |method| public_send(method) }
|
758
|
-
end
|
759
|
-
|
760
788
|
private
|
761
789
|
# +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
|
762
790
|
# the array, and then rescues from the possible +NoMethodError+. If those elements are
|
@@ -771,16 +799,20 @@ module ActiveRecord
|
|
771
799
|
end
|
772
800
|
|
773
801
|
def init_internals
|
774
|
-
@primary_key = self.class.primary_key
|
775
802
|
@readonly = false
|
776
803
|
@previously_new_record = false
|
777
804
|
@destroyed = false
|
778
805
|
@marked_for_destruction = false
|
779
806
|
@destroyed_by_association = nil
|
780
807
|
@_start_transaction_state = nil
|
781
|
-
@strict_loading = self.class.strict_loading_by_default
|
782
808
|
|
783
|
-
self.class
|
809
|
+
klass = self.class
|
810
|
+
|
811
|
+
@primary_key = klass.primary_key
|
812
|
+
@strict_loading = klass.strict_loading_by_default
|
813
|
+
@strict_loading_mode = :all
|
814
|
+
|
815
|
+
klass.define_attribute_methods
|
784
816
|
end
|
785
817
|
|
786
818
|
def initialize_internals_callback
|
@@ -800,5 +832,30 @@ module ActiveRecord
|
|
800
832
|
def inspection_filter
|
801
833
|
self.class.inspection_filter
|
802
834
|
end
|
835
|
+
|
836
|
+
def inspect_with_attributes(attributes_to_list)
|
837
|
+
inspection = if @attributes
|
838
|
+
attributes_to_list.filter_map do |name|
|
839
|
+
name = name.to_s
|
840
|
+
if _has_attribute?(name)
|
841
|
+
"#{name}: #{attribute_for_inspect(name)}"
|
842
|
+
end
|
843
|
+
end.join(", ")
|
844
|
+
else
|
845
|
+
"not initialized"
|
846
|
+
end
|
847
|
+
|
848
|
+
"#<#{self.class} #{inspection}>"
|
849
|
+
end
|
850
|
+
|
851
|
+
def attributes_for_inspect
|
852
|
+
self.class.attributes_for_inspect == :all ? all_attributes_for_inspect : self.class.attributes_for_inspect
|
853
|
+
end
|
854
|
+
|
855
|
+
def all_attributes_for_inspect
|
856
|
+
return [] unless @attributes
|
857
|
+
|
858
|
+
attribute_names
|
859
|
+
end
|
803
860
|
end
|
804
861
|
end
|