activerecord 7.0.8 → 7.1.3.4
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 +1554 -1452
- data/MIT-LICENSE +1 -1
- data/README.rdoc +16 -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 +20 -4
- 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 +15 -9
- data/lib/active_record/associations/collection_proxy.rb +15 -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 -3
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +31 -7
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +313 -217
- 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 +52 -34
- 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 +55 -9
- 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 +74 -51
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +62 -23
- 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 +511 -91
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +207 -108
- 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 +22 -143
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
- 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 +151 -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 +74 -40
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- 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 +10 -6
- 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 +361 -60
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +353 -192
- 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 +52 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +209 -79
- 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 +262 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +72 -95
- data/lib/active_record/core.rb +175 -153
- 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 +9 -4
- 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 +42 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +21 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- 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 +112 -28
- data/lib/active_record/errors.rb +112 -18
- 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 +135 -71
- data/lib/active_record/future_result.rb +31 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +57 -10
- 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 +6 -8
- 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 +139 -5
- 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/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +219 -111
- data/lib/active_record/model_schema.rb +64 -44
- data/lib/active_record/nested_attributes.rb +24 -6
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +188 -37
- 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 -6
- data/lib/active_record/railties/databases.rake +142 -148
- 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 +174 -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 +187 -63
- data/lib/active_record/relation/delegation.rb +23 -9
- 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 +26 -14
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +352 -63
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +91 -35
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +24 -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 +10 -1
- 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 +36 -10
- 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/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/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 +1 -9
- 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 +48 -12
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -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
|
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
class DatabaseConfigurations
|
5
|
-
#
|
5
|
+
# = Active Record Database Hash Config
|
6
|
+
#
|
7
|
+
# A +HashConfig+ object is created for each database configuration entry that
|
6
8
|
# is created from a hash.
|
7
9
|
#
|
8
10
|
# A hash config:
|
@@ -14,19 +16,23 @@ module ActiveRecord
|
|
14
16
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10
|
15
17
|
# @env_name="development", @name="primary", @config={database: "db_name"}>
|
16
18
|
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# * <tt>:env_name</tt> - The Rails environment, i.e. "development".
|
20
|
-
# * <tt>:name</tt> - The db config name. In a standard two-tier
|
21
|
-
# database configuration this will default to "primary". In a multiple
|
22
|
-
# database three-tier database configuration this corresponds to the name
|
23
|
-
# used in the second tier, for example "primary_readonly".
|
24
|
-
# * <tt>:config</tt> - The config hash. This is the hash that contains the
|
25
|
-
# database adapter, name, and other important information for database
|
26
|
-
# connections.
|
19
|
+
# See ActiveRecord::DatabaseConfigurations for more info.
|
27
20
|
class HashConfig < DatabaseConfig
|
28
21
|
attr_reader :configuration_hash
|
29
22
|
|
23
|
+
|
24
|
+
# Initialize a new +HashConfig+ object
|
25
|
+
#
|
26
|
+
# ==== Options
|
27
|
+
#
|
28
|
+
# * <tt>:env_name</tt> - The \Rails environment, i.e. "development".
|
29
|
+
# * <tt>:name</tt> - The db config name. In a standard two-tier
|
30
|
+
# database configuration this will default to "primary". In a multiple
|
31
|
+
# database three-tier database configuration this corresponds to the name
|
32
|
+
# used in the second tier, for example "primary_readonly".
|
33
|
+
# * <tt>:config</tt> - The config hash. This is the hash that contains the
|
34
|
+
# database adapter, name, and other important information for database
|
35
|
+
# connections.
|
30
36
|
def initialize(env_name, name, configuration_hash)
|
31
37
|
super(env_name, name)
|
32
38
|
@configuration_hash = configuration_hash.symbolize_keys.freeze
|
@@ -74,6 +80,10 @@ module ActiveRecord
|
|
74
80
|
(configuration_hash[:max_threads] || pool).to_i
|
75
81
|
end
|
76
82
|
|
83
|
+
def query_cache
|
84
|
+
configuration_hash[:query_cache]
|
85
|
+
end
|
86
|
+
|
77
87
|
def max_queue
|
78
88
|
max_threads * 4
|
79
89
|
end
|
@@ -122,7 +132,7 @@ module ActiveRecord
|
|
122
132
|
# If +configuration_hash[:schema_dump]+ is set to +false+ or +nil+
|
123
133
|
# the schema will not be dumped.
|
124
134
|
#
|
125
|
-
# If the config option is set that will be used. Otherwise Rails
|
135
|
+
# If the config option is set that will be used. Otherwise \Rails
|
126
136
|
# will generate the filename from the database config name.
|
127
137
|
def schema_dump(format = ActiveRecord.schema_format)
|
128
138
|
if configuration_hash.key?(:schema_dump)
|
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
class DatabaseConfigurations
|
5
|
-
#
|
5
|
+
# = Active Record Database Url Config
|
6
|
+
#
|
7
|
+
# A +UrlConfig+ object is created for each database configuration
|
6
8
|
# entry that is created from a URL. This can either be a URL string
|
7
9
|
# or a hash with a URL in place of the config hash.
|
8
10
|
#
|
@@ -17,20 +19,24 @@ module ActiveRecord
|
|
17
19
|
# @config={adapter: "postgresql", database: "foo", host: "localhost"},
|
18
20
|
# @url="postgres://localhost/foo">
|
19
21
|
#
|
20
|
-
#
|
22
|
+
# See ActiveRecord::DatabaseConfigurations for more info.
|
21
23
|
#
|
22
|
-
# * <tt>:env_name</tt> - The Rails environment, i.e. "development".
|
23
|
-
# * <tt>:name</tt> - The db config name. In a standard two-tier
|
24
|
-
# database configuration this will default to "primary". In a multiple
|
25
|
-
# database three-tier database configuration this corresponds to the name
|
26
|
-
# used in the second tier, for example "primary_readonly".
|
27
|
-
# * <tt>:url</tt> - The database URL.
|
28
|
-
# * <tt>:config</tt> - The config hash. This is the hash that contains the
|
29
|
-
# database adapter, name, and other important information for database
|
30
|
-
# connections.
|
31
24
|
class UrlConfig < HashConfig
|
32
25
|
attr_reader :url
|
33
26
|
|
27
|
+
# Initialize a new +UrlConfig+ object
|
28
|
+
#
|
29
|
+
# ==== Options
|
30
|
+
#
|
31
|
+
# * <tt>:env_name</tt> - The \Rails environment, i.e. "development".
|
32
|
+
# * <tt>:name</tt> - The db config name. In a standard two-tier
|
33
|
+
# database configuration this will default to "primary". In a multiple
|
34
|
+
# database three-tier database configuration this corresponds to the name
|
35
|
+
# used in the second tier, for example "primary_readonly".
|
36
|
+
# * <tt>:url</tt> - The database URL.
|
37
|
+
# * <tt>:config</tt> - The config hash. This is the hash that contains the
|
38
|
+
# database adapter, name, and other important information for database
|
39
|
+
# connections.
|
34
40
|
def initialize(env_name, name, url, configuration_hash = {})
|
35
41
|
super(env_name, name, configuration_hash)
|
36
42
|
|
@@ -7,15 +7,69 @@ require "active_record/database_configurations/url_config"
|
|
7
7
|
require "active_record/database_configurations/connection_url_resolver"
|
8
8
|
|
9
9
|
module ActiveRecord
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
10
|
+
# = Active Record Database Configurations
|
11
|
+
#
|
12
|
+
# +ActiveRecord::DatabaseConfigurations+ returns an array of +DatabaseConfig+
|
13
|
+
# objects that are constructed from the application's database
|
14
|
+
# configuration hash or URL string.
|
15
|
+
#
|
16
|
+
# The array of +DatabaseConfig+ objects in an application default to either a
|
17
|
+
# HashConfig or UrlConfig. You can retrieve your application's config by using
|
18
|
+
# ActiveRecord::Base.configurations.
|
19
|
+
#
|
20
|
+
# If you register a custom handler, objects will be created according to the
|
21
|
+
# conditions of the handler. See ::register_db_config_handler for more on
|
22
|
+
# registering custom handlers.
|
13
23
|
class DatabaseConfigurations
|
14
24
|
class InvalidConfigurationError < StandardError; end
|
15
25
|
|
16
26
|
attr_reader :configurations
|
17
27
|
delegate :any?, to: :configurations
|
18
28
|
|
29
|
+
singleton_class.attr_accessor :db_config_handlers # :nodoc:
|
30
|
+
self.db_config_handlers = [] # :nodoc:
|
31
|
+
|
32
|
+
# Allows an application to register a custom handler for database configuration
|
33
|
+
# objects. This is useful for creating a custom handler that responds to
|
34
|
+
# methods your application needs but Active Record doesn't implement. For
|
35
|
+
# example if you are using Vitess, you may want your Vitess configurations
|
36
|
+
# to respond to `sharded?`. To implement this define the following in an
|
37
|
+
# initializer:
|
38
|
+
#
|
39
|
+
# ActiveRecord::DatabaseConfigurations.register_db_config_handler do |env_name, name, url, config|
|
40
|
+
# next unless config.key?(:vitess)
|
41
|
+
# VitessConfig.new(env_name, name, config)
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# Note: applications must handle the condition in which custom config should be
|
45
|
+
# created in your handler registration otherwise all objects will use the custom
|
46
|
+
# handler.
|
47
|
+
#
|
48
|
+
# Then define your +VitessConfig+ to respond to the methods your application
|
49
|
+
# needs. It is recommended that you inherit from one of the existing
|
50
|
+
# database config classes to avoid having to reimplement all methods. Custom
|
51
|
+
# config handlers should only implement methods Active Record does not.
|
52
|
+
#
|
53
|
+
# class VitessConfig < ActiveRecord::DatabaseConfigurations::UrlConfig
|
54
|
+
# def sharded?
|
55
|
+
# configuration_hash.fetch("sharded", false)
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# For configs that have a +:vitess+ key, a +VitessConfig+ object will be
|
60
|
+
# created instead of a +UrlConfig+.
|
61
|
+
def self.register_db_config_handler(&block)
|
62
|
+
db_config_handlers << block
|
63
|
+
end
|
64
|
+
|
65
|
+
register_db_config_handler do |env_name, name, url, config|
|
66
|
+
if url
|
67
|
+
UrlConfig.new(env_name, name, url, config)
|
68
|
+
else
|
69
|
+
HashConfig.new(env_name, name, config)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
19
73
|
def initialize(configurations = {})
|
20
74
|
@configurations = build_configs(configurations)
|
21
75
|
end
|
@@ -23,8 +77,8 @@ module ActiveRecord
|
|
23
77
|
# Collects the configs for the environment and optionally the specification
|
24
78
|
# name passed in. To include replica configurations pass <tt>include_hidden: true</tt>.
|
25
79
|
#
|
26
|
-
# If a name is provided a single DatabaseConfig object will be
|
27
|
-
# returned, otherwise an array of DatabaseConfig objects will be
|
80
|
+
# If a name is provided a single +DatabaseConfig+ object will be
|
81
|
+
# returned, otherwise an array of +DatabaseConfig+ objects will be
|
28
82
|
# returned that corresponds with the environment and type requested.
|
29
83
|
#
|
30
84
|
# ==== Options
|
@@ -34,20 +88,14 @@ module ActiveRecord
|
|
34
88
|
# * <tt>name:</tt> The db config name (i.e. primary, animals, etc.). Defaults
|
35
89
|
# to +nil+. If no +env_name+ is specified the config for the default env and the
|
36
90
|
# passed +name+ will be returned.
|
37
|
-
# * <tt>
|
38
|
-
#
|
39
|
-
#
|
40
|
-
# Defaults to +false+.
|
91
|
+
# * <tt>config_key:</tt> Selects configs that contain a particular key in the configuration
|
92
|
+
# hash. Useful for selecting configs that use a custom db config handler or finding
|
93
|
+
# configs with hashes that contain a particular key.
|
41
94
|
# * <tt>include_hidden:</tt> Determines whether to include replicas and configurations
|
42
|
-
# hidden by
|
95
|
+
# hidden by <tt>database_tasks: false</tt> in the returned list. Most of the time we're only
|
43
96
|
# iterating over the primary connections (i.e. migrations don't need to run for the
|
44
97
|
# write and read connection). Defaults to +false+.
|
45
|
-
def configs_for(env_name: nil, name: nil,
|
46
|
-
if include_replicas
|
47
|
-
include_hidden = include_replicas
|
48
|
-
ActiveSupport::Deprecation.warn("The kwarg `include_replicas` is deprecated in favor of `include_hidden`. When `include_hidden` is passed, configurations with `replica: true` or `database_tasks: false` will be returned. `include_replicas` will be removed in Rails 7.1.")
|
49
|
-
end
|
50
|
-
|
98
|
+
def configs_for(env_name: nil, name: nil, config_key: nil, include_hidden: false)
|
51
99
|
env_name ||= default_env if name
|
52
100
|
configs = env_with_configs(env_name)
|
53
101
|
|
@@ -57,6 +105,12 @@ module ActiveRecord
|
|
57
105
|
end
|
58
106
|
end
|
59
107
|
|
108
|
+
if config_key
|
109
|
+
configs = configs.select do |db_config|
|
110
|
+
db_config.configuration_hash.key?(config_key)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
60
114
|
if name
|
61
115
|
configs.find do |db_config|
|
62
116
|
db_config.name == name
|
@@ -66,17 +120,17 @@ module ActiveRecord
|
|
66
120
|
end
|
67
121
|
end
|
68
122
|
|
69
|
-
# Returns a single DatabaseConfig object based on the requested environment.
|
123
|
+
# Returns a single +DatabaseConfig+ object based on the requested environment.
|
70
124
|
#
|
71
125
|
# If the application has multiple databases +find_db_config+ will return
|
72
|
-
# the first DatabaseConfig for the environment.
|
126
|
+
# the first +DatabaseConfig+ for the environment.
|
73
127
|
def find_db_config(env)
|
74
|
-
|
75
|
-
|
76
|
-
.
|
77
|
-
|
78
|
-
|
79
|
-
|
128
|
+
env = env.to_s
|
129
|
+
configurations.find do |db_config|
|
130
|
+
db_config.for_current_env? && (db_config.env_name == env || db_config.name == env)
|
131
|
+
end || configurations.find do |db_config|
|
132
|
+
db_config.env_name == env
|
133
|
+
end
|
80
134
|
end
|
81
135
|
|
82
136
|
# A primary configuration is one that is named primary or if there is
|
@@ -93,8 +147,6 @@ module ActiveRecord
|
|
93
147
|
end
|
94
148
|
|
95
149
|
# Checks if the application's configurations are empty.
|
96
|
-
#
|
97
|
-
# Aliased to blank?
|
98
150
|
def empty?
|
99
151
|
configurations.empty?
|
100
152
|
end
|
@@ -219,15 +271,16 @@ module ActiveRecord
|
|
219
271
|
end
|
220
272
|
|
221
273
|
def build_db_config_from_hash(env_name, name, config)
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
config_without_url.delete :url
|
274
|
+
url = config[:url]
|
275
|
+
config_without_url = config.dup
|
276
|
+
config_without_url.delete :url
|
226
277
|
|
227
|
-
|
228
|
-
|
229
|
-
|
278
|
+
DatabaseConfigurations.db_config_handlers.reverse_each do |handler|
|
279
|
+
config = handler.call(env_name, name, url, config_without_url)
|
280
|
+
return config if config
|
230
281
|
end
|
282
|
+
|
283
|
+
nil
|
231
284
|
end
|
232
285
|
|
233
286
|
def merge_db_environment_variables(current_env, configs)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_support/core_ext/string/inquiry"
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
|
-
#
|
6
|
+
# = Delegated types
|
7
7
|
#
|
8
8
|
# Class hierarchies can map to relational database tables in many ways. Active Record, for example, offers
|
9
9
|
# purely abstract classes, where the superclass doesn't persist any attributes, and single-table inheritance,
|
@@ -138,7 +138,7 @@ module ActiveRecord
|
|
138
138
|
#
|
139
139
|
# Now you can list a bunch of entries, call <tt>Entry#title</tt>, and polymorphism will provide you with the answer.
|
140
140
|
#
|
141
|
-
# == Nested Attributes
|
141
|
+
# == Nested \Attributes
|
142
142
|
#
|
143
143
|
# Enabling nested attributes on a delegated_type association allows you to
|
144
144
|
# create the entry and message in one go:
|
@@ -192,6 +192,11 @@ module ActiveRecord
|
|
192
192
|
# +role+ with an "_id" suffix. So a class that defines a
|
193
193
|
# <tt>delegated_type :entryable, types: %w[ Message Comment ]</tt> association will use "entryable_id" as
|
194
194
|
# the default <tt>:foreign_key</tt>.
|
195
|
+
# [:foreign_type]
|
196
|
+
# Specify the column used to store the associated object's type. By default this is inferred to be the passed
|
197
|
+
# +role+ with a "_type" suffix. A class that defines a
|
198
|
+
# <tt>delegated_type :entryable, types: %w[ Message Comment ]</tt> association will use "entryable_type" as
|
199
|
+
# the default <tt>:foreign_type</tt>.
|
195
200
|
# [:primary_key]
|
196
201
|
# Specify the method that returns the primary key of associated object used for the convenience methods.
|
197
202
|
# By default this is +id+.
|
@@ -211,11 +216,11 @@ module ActiveRecord
|
|
211
216
|
private
|
212
217
|
def define_delegated_type_methods(role, types:, options:)
|
213
218
|
primary_key = options[:primary_key] || "id"
|
214
|
-
role_type = "#{role}_type"
|
219
|
+
role_type = options[:foreign_type] || "#{role}_type"
|
215
220
|
role_id = options[:foreign_key] || "#{role}_id"
|
216
221
|
|
217
222
|
define_method "#{role}_class" do
|
218
|
-
public_send(
|
223
|
+
public_send(role_type).constantize
|
219
224
|
end
|
220
225
|
|
221
226
|
define_method "#{role}_name" do
|
@@ -4,6 +4,8 @@ module ActiveRecord
|
|
4
4
|
class DestroyAssociationAsyncError < StandardError
|
5
5
|
end
|
6
6
|
|
7
|
+
# = Active Record Destroy Association Async Job
|
8
|
+
#
|
7
9
|
# Job to destroy the records associated with a destroyed record in background.
|
8
10
|
class DestroyAssociationAsyncJob < ActiveJob::Base
|
9
11
|
queue_as { ActiveRecord.queues[:destroy] }
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Encryption
|
5
|
+
class AutoFilteredParameters
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
@attributes_by_class = Concurrent::Map.new
|
9
|
+
@collecting = true
|
10
|
+
|
11
|
+
install_collecting_hook
|
12
|
+
end
|
13
|
+
|
14
|
+
def enable
|
15
|
+
apply_collected_attributes
|
16
|
+
@collecting = false
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
attr_reader :app
|
21
|
+
|
22
|
+
def install_collecting_hook
|
23
|
+
ActiveRecord::Encryption.on_encrypted_attribute_declared do |klass, attribute|
|
24
|
+
attribute_was_declared(klass, attribute)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def attribute_was_declared(klass, attribute)
|
29
|
+
if collecting?
|
30
|
+
collect_for_later(klass, attribute)
|
31
|
+
else
|
32
|
+
apply_filter(klass, attribute)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def apply_collected_attributes
|
37
|
+
@attributes_by_class.each do |klass, attributes|
|
38
|
+
attributes.each do |attribute|
|
39
|
+
apply_filter(klass, attribute)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def collecting?
|
45
|
+
@collecting
|
46
|
+
end
|
47
|
+
|
48
|
+
def collect_for_later(klass, attribute)
|
49
|
+
@attributes_by_class[klass] ||= Concurrent::Array.new
|
50
|
+
@attributes_by_class[klass] << attribute
|
51
|
+
end
|
52
|
+
|
53
|
+
def apply_filter(klass, attribute)
|
54
|
+
filter = [("#{klass.model_name.element}" if klass.name), attribute.to_s].compact.join(".")
|
55
|
+
unless excluded_from_filter_parameters?(filter)
|
56
|
+
app.config.filter_parameters << filter unless app.config.filter_parameters.include?(filter)
|
57
|
+
klass.filter_attributes += [ attribute ]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def excluded_from_filter_parameters?(filter_parameter)
|
62
|
+
ActiveRecord::Encryption.config.excluded_from_filter_parameters.find { |excluded_filter| excluded_filter.to_s == filter_parameter }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "openssl"
|
4
|
-
require "base64"
|
5
4
|
|
6
5
|
module ActiveRecord
|
7
6
|
module Encryption
|
@@ -80,6 +79,10 @@ module ActiveRecord
|
|
80
79
|
raise ActiveRecord::Encryption::Errors::Decryption
|
81
80
|
end
|
82
81
|
|
82
|
+
def inspect # :nodoc:
|
83
|
+
"#<#{self.class.name}:#{'%#016x' % (object_id << 1)}>"
|
84
|
+
end
|
85
|
+
|
83
86
|
private
|
84
87
|
def generate_iv(cipher, clear_text)
|
85
88
|
if @deterministic
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "openssl"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module Encryption
|
5
7
|
# Container of configuration options
|
6
8
|
class Config
|
7
|
-
attr_accessor :primary_key, :deterministic_key, :store_key_references, :key_derivation_salt,
|
9
|
+
attr_accessor :primary_key, :deterministic_key, :store_key_references, :key_derivation_salt, :hash_digest_class,
|
8
10
|
:support_unencrypted_data, :encrypt_fixtures, :validate_column_size, :add_to_filter_parameters,
|
9
11
|
:excluded_from_filter_parameters, :extend_queries, :previous_schemes, :forced_encoding_for_deterministic_encryption
|
10
12
|
|
@@ -21,6 +23,27 @@ module ActiveRecord
|
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
26
|
+
def support_sha1_for_non_deterministic_encryption=(value)
|
27
|
+
if value && has_primary_key?
|
28
|
+
sha1_key_generator = ActiveRecord::Encryption::KeyGenerator.new(hash_digest_class: OpenSSL::Digest::SHA1)
|
29
|
+
sha1_key_provider = ActiveRecord::Encryption::DerivedSecretKeyProvider.new(primary_key, key_generator: sha1_key_generator)
|
30
|
+
add_previous_scheme key_provider: sha1_key_provider
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
%w(key_derivation_salt primary_key deterministic_key).each do |key|
|
35
|
+
silence_redefinition_of_method "has_#{key}?"
|
36
|
+
define_method("has_#{key}?") do
|
37
|
+
instance_variable_get(:"@#{key}").presence
|
38
|
+
end
|
39
|
+
|
40
|
+
silence_redefinition_of_method key
|
41
|
+
define_method(key) do
|
42
|
+
public_send("has_#{key}?") or
|
43
|
+
raise Errors::Configuration, "Missing Active Record encryption credential: active_record_encryption.#{key}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
24
47
|
private
|
25
48
|
def set_defaults
|
26
49
|
self.store_key_references = false
|
@@ -31,6 +54,7 @@ module ActiveRecord
|
|
31
54
|
self.excluded_from_filter_parameters = []
|
32
55
|
self.previous_schemes = []
|
33
56
|
self.forced_encoding_for_deterministic_encryption = Encoding::UTF_8
|
57
|
+
self.hash_digest_class = OpenSSL::Digest::SHA1
|
34
58
|
|
35
59
|
# TODO: Setting to false for now as the implementation is a bit experimental
|
36
60
|
self.extend_queries = false
|
@@ -17,24 +17,29 @@ module ActiveRecord
|
|
17
17
|
delegate name, to: :context
|
18
18
|
end
|
19
19
|
|
20
|
-
def configure(primary_key
|
20
|
+
def configure(primary_key: nil, deterministic_key: nil, key_derivation_salt: nil, **properties) # :nodoc:
|
21
21
|
config.primary_key = primary_key
|
22
22
|
config.deterministic_key = deterministic_key
|
23
23
|
config.key_derivation_salt = key_derivation_salt
|
24
24
|
|
25
|
-
|
25
|
+
# Set the default for this property here instead of in +Config#set_defaults+ as this needs
|
26
|
+
# to happen *after* the keys have been set.
|
27
|
+
properties[:support_sha1_for_non_deterministic_encryption] = true if properties[:support_sha1_for_non_deterministic_encryption].nil?
|
26
28
|
|
27
29
|
properties.each do |name, value|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
ActiveRecord::Encryption.config.send "#{name}=", value if ActiveRecord::Encryption.config.respond_to?("#{name}=")
|
31
|
+
end
|
32
|
+
|
33
|
+
ActiveRecord::Encryption.reset_default_context
|
34
|
+
|
35
|
+
properties.each do |name, value|
|
36
|
+
ActiveRecord::Encryption.context.send "#{name}=", value if ActiveRecord::Encryption.context.respond_to?("#{name}=")
|
32
37
|
end
|
33
38
|
end
|
34
39
|
|
35
40
|
# Register callback to be invoked when an encrypted attribute is declared.
|
36
41
|
#
|
37
|
-
# === Example
|
42
|
+
# === Example
|
38
43
|
#
|
39
44
|
# ActiveRecord::Encryption.on_encrypted_attribute_declared do |klass, attribute_name|
|
40
45
|
# ...
|
@@ -49,18 +54,6 @@ module ActiveRecord
|
|
49
54
|
block.call(klass, name)
|
50
55
|
end
|
51
56
|
end
|
52
|
-
|
53
|
-
def install_auto_filtered_parameters_hook(application) # :nodoc:
|
54
|
-
ActiveRecord::Encryption.on_encrypted_attribute_declared do |klass, encrypted_attribute_name|
|
55
|
-
filter_parameter = [("#{klass.model_name.element}" if klass.name), encrypted_attribute_name.to_s].compact.join(".")
|
56
|
-
application.config.filter_parameters << filter_parameter unless excluded_from_filter_parameters?(filter_parameter)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
def excluded_from_filter_parameters?(filter_parameter)
|
62
|
-
ActiveRecord::Encryption.config.excluded_from_filter_parameters.find { |excluded_filter| excluded_filter.to_s == filter_parameter }
|
63
|
-
end
|
64
57
|
end
|
65
58
|
end
|
66
59
|
end
|
@@ -12,9 +12,7 @@ module ActiveRecord
|
|
12
12
|
class Context
|
13
13
|
PROPERTIES = %i[ key_provider key_generator cipher message_serializer encryptor frozen_encryption ]
|
14
14
|
|
15
|
-
PROPERTIES
|
16
|
-
attr_accessor name
|
17
|
-
end
|
15
|
+
attr_accessor(*PROPERTIES)
|
18
16
|
|
19
17
|
def initialize
|
20
18
|
set_defaults
|
@@ -22,6 +20,11 @@ module ActiveRecord
|
|
22
20
|
|
23
21
|
alias frozen_encryption? frozen_encryption
|
24
22
|
|
23
|
+
silence_redefinition_of_method :key_provider
|
24
|
+
def key_provider
|
25
|
+
@key_provider ||= build_default_key_provider
|
26
|
+
end
|
27
|
+
|
25
28
|
private
|
26
29
|
def set_defaults
|
27
30
|
self.frozen_encryption = false
|
@@ -30,6 +33,10 @@ module ActiveRecord
|
|
30
33
|
self.encryptor = ActiveRecord::Encryption::Encryptor.new
|
31
34
|
self.message_serializer = ActiveRecord::Encryption::MessageSerializer.new
|
32
35
|
end
|
36
|
+
|
37
|
+
def build_default_key_provider
|
38
|
+
ActiveRecord::Encryption::DerivedSecretKeyProvider.new(ActiveRecord::Encryption.config.primary_key)
|
39
|
+
end
|
33
40
|
end
|
34
41
|
end
|
35
42
|
end
|
@@ -14,7 +14,7 @@ module ActiveRecord
|
|
14
14
|
extend ActiveSupport::Concern
|
15
15
|
|
16
16
|
included do
|
17
|
-
|
17
|
+
mattr_accessor :default_context, default: Context.new
|
18
18
|
thread_mattr_accessor :custom_contexts
|
19
19
|
end
|
20
20
|
|
@@ -66,6 +66,10 @@ module ActiveRecord
|
|
66
66
|
def current_custom_context
|
67
67
|
self.custom_contexts&.last
|
68
68
|
end
|
69
|
+
|
70
|
+
def reset_default_context
|
71
|
+
self.default_context = Context.new
|
72
|
+
end
|
69
73
|
end
|
70
74
|
end
|
71
75
|
end
|
@@ -4,9 +4,15 @@ module ActiveRecord
|
|
4
4
|
module Encryption
|
5
5
|
# A KeyProvider that derives keys from passwords.
|
6
6
|
class DerivedSecretKeyProvider < KeyProvider
|
7
|
-
def initialize(passwords)
|
8
|
-
super(Array(passwords).collect { |password|
|
7
|
+
def initialize(passwords, key_generator: ActiveRecord::Encryption.key_generator)
|
8
|
+
super(Array(passwords).collect { |password| derive_key_from(password, using: key_generator) })
|
9
9
|
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def derive_key_from(password, using: key_generator)
|
13
|
+
secret = using.derive_key_from(password)
|
14
|
+
ActiveRecord::Encryption::Key.new(secret)
|
15
|
+
end
|
10
16
|
end
|
11
17
|
end
|
12
18
|
end
|