activerecord 7.0.8.7 → 7.2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +631 -1944
- data/MIT-LICENSE +1 -1
- data/README.rdoc +29 -29
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +23 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +26 -14
- data/lib/active_record/associations/collection_proxy.rb +29 -11
- 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 +21 -14
- data/lib/active_record/associations/has_many_through_association.rb +17 -7
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +354 -485
- data/lib/active_record/attribute_assignment.rb +0 -4
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +131 -32
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +148 -33
- data/lib/active_record/attributes.rb +64 -50
- data/lib/active_record/autosave_association.rb +69 -37
- data/lib/active_record/base.rb +9 -5
- data/lib/active_record/callbacks.rb +11 -25
- 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 +123 -131
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +323 -88
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +217 -63
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
- 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 +307 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +510 -111
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +278 -125
- 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 +26 -139
- data/lib/active_record/connection_adapters/mysql/quoting.rb +53 -54
- 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 +25 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- 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 +100 -43
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- 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 +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
- 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 +151 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +370 -63
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +367 -201
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +50 -8
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -110
- 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 +124 -1
- data/lib/active_record/connection_handling.rb +96 -104
- data/lib/active_record/core.rb +251 -176
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +39 -10
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- 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 +45 -21
- data/lib/active_record/encryption/encrypted_attribute_type.rb +47 -12
- data/lib/active_record/encryption/encryptor.rb +18 -3
- 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/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +129 -28
- data/lib/active_record/errors.rb +151 -31
- data/lib/active_record/explain.rb +21 -12
- 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 +167 -97
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +11 -8
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +18 -22
- 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 +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 +106 -8
- data/lib/active_record/migration/compatibility.rb +147 -5
- 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/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +234 -117
- data/lib/active_record/model_schema.rb +90 -102
- data/lib/active_record/nested_attributes.rb +48 -11
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +168 -339
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +92 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +33 -8
- data/lib/active_record/railtie.rb +129 -85
- data/lib/active_record/railties/controller_runtime.rb +22 -7
- data/lib/active_record/railties/databases.rake +145 -154
- 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 +267 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +250 -93
- data/lib/active_record/relation/delegation.rb +30 -19
- data/lib/active_record/relation/finder_methods.rb +93 -18
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +18 -3
- 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 +28 -16
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +576 -107
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +580 -90
- data/lib/active_record/result.rb +49 -48
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +70 -25
- data/lib/active_record/schema.rb +8 -7
- data/lib/active_record/schema_dumper.rb +63 -14
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +3 -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 +27 -6
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +190 -118
- 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 +16 -7
- data/lib/active_record/test_fixtures.rb +170 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- 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 +106 -24
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type/time.rb +4 -0
- 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 +9 -3
- 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 +61 -11
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +247 -33
- data/lib/arel/alias_predication.rb +1 -1
- 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/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -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/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +112 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- 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
- metadata +54 -12
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "base64"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module Encryption
|
5
7
|
# A message serializer that serializes +Messages+ with JSON.
|
@@ -31,6 +33,10 @@ module ActiveRecord
|
|
31
33
|
JSON.dump message_to_json(message)
|
32
34
|
end
|
33
35
|
|
36
|
+
def binary?
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
34
40
|
private
|
35
41
|
def parse_message(data, level)
|
36
42
|
validate_message_data_format(data, level)
|
@@ -14,10 +14,10 @@ module ActiveRecord
|
|
14
14
|
#
|
15
15
|
# See +Properties::DEFAULT_PROPERTIES+, Key, Message
|
16
16
|
class Properties
|
17
|
-
ALLOWED_VALUE_CLASSES = [String, ActiveRecord::Encryption::Message, Numeric, TrueClass, FalseClass, Symbol, NilClass]
|
17
|
+
ALLOWED_VALUE_CLASSES = [String, ActiveRecord::Encryption::Message, Numeric, Integer, Float, BigDecimal, TrueClass, FalseClass, Symbol, NilClass]
|
18
18
|
|
19
19
|
delegate_missing_to :data
|
20
|
-
delegate :==, to: :data
|
20
|
+
delegate :==, :[], :each, :key?, to: :data
|
21
21
|
|
22
22
|
# For each entry it generates an accessor exposing the full name
|
23
23
|
DEFAULT_PROPERTIES = {
|
@@ -54,7 +54,7 @@ module ActiveRecord
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def validate_value_type(value)
|
57
|
-
unless ALLOWED_VALUE_CLASSES.
|
57
|
+
unless ALLOWED_VALUE_CLASSES.include?(value.class) || ALLOWED_VALUE_CLASSES.any? { |klass| value.is_a?(klass) }
|
58
58
|
raise ActiveRecord::Encryption::Errors::ForbiddenClass, "Can't store a #{value.class}, only properties of type #{ALLOWED_VALUE_CLASSES.inspect} are allowed"
|
59
59
|
end
|
60
60
|
end
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
10
10
|
class Scheme
|
11
11
|
attr_accessor :previous_schemes
|
12
12
|
|
13
|
-
def initialize(key_provider: nil, key: nil, deterministic: nil, downcase: nil, ignore_case: nil,
|
13
|
+
def initialize(key_provider: nil, key: nil, deterministic: nil, support_unencrypted_data: nil, downcase: nil, ignore_case: nil,
|
14
14
|
previous_schemes: nil, **context_properties)
|
15
15
|
# Initializing all attributes to +nil+ as we want to allow a "not set" semantics so that we
|
16
16
|
# can merge schemes without overriding values with defaults. See +#merge+
|
@@ -18,6 +18,7 @@ module ActiveRecord
|
|
18
18
|
@key_provider_param = key_provider
|
19
19
|
@key = key
|
20
20
|
@deterministic = deterministic
|
21
|
+
@support_unencrypted_data = support_unencrypted_data
|
21
22
|
@downcase = downcase || ignore_case
|
22
23
|
@ignore_case = ignore_case
|
23
24
|
@previous_schemes_param = previous_schemes
|
@@ -36,7 +37,11 @@ module ActiveRecord
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def deterministic?
|
39
|
-
|
40
|
+
!!@deterministic
|
41
|
+
end
|
42
|
+
|
43
|
+
def support_unencrypted_data?
|
44
|
+
@support_unencrypted_data.nil? ? ActiveRecord::Encryption.config.support_unencrypted_data : @support_unencrypted_data
|
40
45
|
end
|
41
46
|
|
42
47
|
def fixed?
|
@@ -45,10 +50,7 @@ module ActiveRecord
|
|
45
50
|
end
|
46
51
|
|
47
52
|
def key_provider
|
48
|
-
@
|
49
|
-
validate_keys!
|
50
|
-
@key_provider_param || build_key_provider
|
51
|
-
end
|
53
|
+
@key_provider_param || key_provider_from_key || deterministic_key_provider || default_key_provider
|
52
54
|
end
|
53
55
|
|
54
56
|
def merge(other_scheme)
|
@@ -56,7 +58,7 @@ module ActiveRecord
|
|
56
58
|
end
|
57
59
|
|
58
60
|
def to_h
|
59
|
-
{ key_provider: @key_provider_param,
|
61
|
+
{ key_provider: @key_provider_param, deterministic: @deterministic, downcase: @downcase, ignore_case: @ignore_case,
|
60
62
|
previous_schemes: @previous_schemes_param, **@context_properties }.compact
|
61
63
|
end
|
62
64
|
|
@@ -68,31 +70,30 @@ module ActiveRecord
|
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
73
|
+
def compatible_with?(other_scheme)
|
74
|
+
deterministic? == other_scheme.deterministic?
|
75
|
+
end
|
76
|
+
|
71
77
|
private
|
72
78
|
def validate_config!
|
73
79
|
raise Errors::Configuration, "ignore_case: can only be used with deterministic encryption" if @ignore_case && !@deterministic
|
74
80
|
raise Errors::Configuration, "key_provider: and key: can't be used simultaneously" if @key_provider_param && @key
|
75
81
|
end
|
76
82
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
|
83
|
+
def key_provider_from_key
|
84
|
+
@key_provider_from_key ||= if @key.present?
|
85
|
+
DerivedSecretKeyProvider.new(@key)
|
86
|
+
end
|
81
87
|
end
|
82
88
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
"active_record_encryption.#{key} or by setting config.active_record.encryption.#{key}"
|
89
|
+
def deterministic_key_provider
|
90
|
+
@deterministic_key_provider ||= if @deterministic
|
91
|
+
DeterministicKeyProvider.new(ActiveRecord::Encryption.config.deterministic_key)
|
87
92
|
end
|
88
93
|
end
|
89
94
|
|
90
|
-
def
|
91
|
-
|
92
|
-
|
93
|
-
if @deterministic && (deterministic_key = ActiveRecord::Encryption.config.deterministic_key)
|
94
|
-
DeterministicKeyProvider.new(deterministic_key)
|
95
|
-
end
|
95
|
+
def default_key_provider
|
96
|
+
ActiveRecord::Encryption.key_provider
|
96
97
|
end
|
97
98
|
end
|
98
99
|
end
|
@@ -8,6 +8,7 @@ module ActiveRecord
|
|
8
8
|
extend ActiveSupport::Autoload
|
9
9
|
|
10
10
|
eager_autoload do
|
11
|
+
autoload :AutoFilteredParameters
|
11
12
|
autoload :Cipher
|
12
13
|
autoload :Config
|
13
14
|
autoload :Configurable
|
@@ -52,4 +53,6 @@ module ActiveRecord
|
|
52
53
|
Cipher.eager_load!
|
53
54
|
end
|
54
55
|
end
|
56
|
+
|
57
|
+
ActiveSupport.run_load_hooks :active_record_encryption, Encryption
|
55
58
|
end
|
data/lib/active_record/enum.rb
CHANGED
@@ -111,23 +111,70 @@ module ActiveRecord
|
|
111
111
|
#
|
112
112
|
# conversation.comments_inactive!
|
113
113
|
# conversation.comments_active? # => false
|
114
|
+
#
|
115
|
+
# If you want to disable the auto-generated methods on the model, you can do
|
116
|
+
# so by setting the +:instance_methods+ option to false:
|
117
|
+
#
|
118
|
+
# class Conversation < ActiveRecord::Base
|
119
|
+
# enum :status, [ :active, :archived ], instance_methods: false
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# If you want the enum value to be validated before saving, use the option +:validate+:
|
123
|
+
#
|
124
|
+
# class Conversation < ActiveRecord::Base
|
125
|
+
# enum :status, [ :active, :archived ], validate: true
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# conversation = Conversation.new
|
129
|
+
#
|
130
|
+
# conversation.status = :unknown
|
131
|
+
# conversation.valid? # => false
|
132
|
+
#
|
133
|
+
# conversation.status = nil
|
134
|
+
# conversation.valid? # => false
|
135
|
+
#
|
136
|
+
# conversation.status = :active
|
137
|
+
# conversation.valid? # => true
|
138
|
+
#
|
139
|
+
# It is also possible to pass additional validation options:
|
140
|
+
#
|
141
|
+
# class Conversation < ActiveRecord::Base
|
142
|
+
# enum :status, [ :active, :archived ], validate: { allow_nil: true }
|
143
|
+
# end
|
144
|
+
#
|
145
|
+
# conversation = Conversation.new
|
146
|
+
#
|
147
|
+
# conversation.status = :unknown
|
148
|
+
# conversation.valid? # => false
|
149
|
+
#
|
150
|
+
# conversation.status = nil
|
151
|
+
# conversation.valid? # => true
|
152
|
+
#
|
153
|
+
# conversation.status = :active
|
154
|
+
# conversation.valid? # => true
|
155
|
+
#
|
156
|
+
# Otherwise +ArgumentError+ will raise:
|
157
|
+
#
|
158
|
+
# class Conversation < ActiveRecord::Base
|
159
|
+
# enum :status, [ :active, :archived ]
|
160
|
+
# end
|
161
|
+
#
|
162
|
+
# conversation = Conversation.new
|
163
|
+
#
|
164
|
+
# conversation.status = :unknown # 'unknown' is not a valid status (ArgumentError)
|
114
165
|
module Enum
|
115
166
|
def self.extended(base) # :nodoc:
|
116
167
|
base.class_attribute(:defined_enums, instance_writer: false, default: {})
|
117
168
|
end
|
118
169
|
|
119
|
-
def inherited(base) # :nodoc:
|
120
|
-
base.defined_enums = defined_enums.deep_dup
|
121
|
-
super
|
122
|
-
end
|
123
|
-
|
124
170
|
class EnumType < Type::Value # :nodoc:
|
125
171
|
delegate :type, to: :subtype
|
126
172
|
|
127
|
-
def initialize(name, mapping, subtype)
|
173
|
+
def initialize(name, mapping, subtype, raise_on_invalid_values: true)
|
128
174
|
@name = name
|
129
175
|
@mapping = mapping
|
130
176
|
@subtype = subtype
|
177
|
+
@_raise_on_invalid_values = raise_on_invalid_values
|
131
178
|
end
|
132
179
|
|
133
180
|
def cast(value)
|
@@ -153,6 +200,8 @@ module ActiveRecord
|
|
153
200
|
end
|
154
201
|
|
155
202
|
def assert_valid_value(value)
|
203
|
+
return unless @_raise_on_invalid_values
|
204
|
+
|
156
205
|
unless value.blank? || mapping.has_key?(value) || mapping.has_value?(value)
|
157
206
|
raise ArgumentError, "'#{value}' is not a valid #{name}"
|
158
207
|
end
|
@@ -170,15 +219,28 @@ module ActiveRecord
|
|
170
219
|
return _enum(name, values, **options)
|
171
220
|
end
|
172
221
|
|
173
|
-
definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default)
|
222
|
+
definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default, :_instance_methods)
|
174
223
|
options.transform_keys! { |key| :"#{key[1..-1]}" }
|
175
224
|
|
176
225
|
definitions.each { |name, values| _enum(name, values, **options) }
|
226
|
+
|
227
|
+
ActiveRecord.deprecator.warn(<<~MSG)
|
228
|
+
Defining enums with keyword arguments is deprecated and will be removed
|
229
|
+
in Rails 8.0. Positional arguments should be used instead:
|
230
|
+
|
231
|
+
#{definitions.map { |name, values| "enum :#{name}, #{values}" }.join("\n")}
|
232
|
+
MSG
|
177
233
|
end
|
178
234
|
|
179
235
|
private
|
180
|
-
def
|
236
|
+
def inherited(base)
|
237
|
+
base.defined_enums = defined_enums.deep_dup
|
238
|
+
super
|
239
|
+
end
|
240
|
+
|
241
|
+
def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
|
181
242
|
assert_valid_enum_definition_values(values)
|
243
|
+
assert_valid_enum_options(options)
|
182
244
|
# statuses = { }
|
183
245
|
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
184
246
|
name = name.to_s
|
@@ -191,9 +253,17 @@ module ActiveRecord
|
|
191
253
|
detect_enum_conflict!(name, name)
|
192
254
|
detect_enum_conflict!(name, "#{name}=")
|
193
255
|
|
194
|
-
attribute(name, **options)
|
256
|
+
attribute(name, **options)
|
257
|
+
|
258
|
+
decorate_attributes([name]) do |_name, subtype|
|
259
|
+
if subtype == ActiveModel::Type.default_value
|
260
|
+
raise "Undeclared attribute type for enum '#{name}' in #{self.name}. Enums must be" \
|
261
|
+
" backed by a database column or declared with an explicit type" \
|
262
|
+
" via `attribute`."
|
263
|
+
end
|
264
|
+
|
195
265
|
subtype = subtype.subtype if EnumType === subtype
|
196
|
-
EnumType.new(name, enum_values, subtype)
|
266
|
+
EnumType.new(name, enum_values, subtype, raise_on_invalid_values: !validate)
|
197
267
|
end
|
198
268
|
|
199
269
|
value_method_names = []
|
@@ -213,18 +283,24 @@ module ActiveRecord
|
|
213
283
|
|
214
284
|
value_method_name = "#{prefix}#{label}#{suffix}"
|
215
285
|
value_method_names << value_method_name
|
216
|
-
define_enum_methods(name, value_method_name, value, scopes)
|
286
|
+
define_enum_methods(name, value_method_name, value, scopes, instance_methods)
|
217
287
|
|
218
288
|
method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
|
219
289
|
value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
|
220
290
|
|
221
291
|
if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
|
222
292
|
value_method_names << value_method_alias
|
223
|
-
define_enum_methods(name, value_method_alias, value, scopes)
|
293
|
+
define_enum_methods(name, value_method_alias, value, scopes, instance_methods)
|
224
294
|
end
|
225
295
|
end
|
226
296
|
end
|
227
297
|
detect_negative_enum_conditions!(value_method_names) if scopes
|
298
|
+
|
299
|
+
if validate
|
300
|
+
validate = {} unless Hash === validate
|
301
|
+
validates_inclusion_of name, in: enum_values.keys, **validate
|
302
|
+
end
|
303
|
+
|
228
304
|
enum_values.freeze
|
229
305
|
end
|
230
306
|
|
@@ -236,21 +312,23 @@ module ActiveRecord
|
|
236
312
|
private
|
237
313
|
attr_reader :klass
|
238
314
|
|
239
|
-
def define_enum_methods(name, value_method_name, value, scopes)
|
240
|
-
|
241
|
-
|
242
|
-
|
315
|
+
def define_enum_methods(name, value_method_name, value, scopes, instance_methods)
|
316
|
+
if instance_methods
|
317
|
+
# def active?() status_for_database == 0 end
|
318
|
+
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
|
319
|
+
define_method("#{value_method_name}?") { public_send(:"#{name}_for_database") == value }
|
243
320
|
|
244
|
-
|
245
|
-
|
246
|
-
|
321
|
+
# def active!() update!(status: 0) end
|
322
|
+
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
|
323
|
+
define_method("#{value_method_name}!") { update!(name => value) }
|
324
|
+
end
|
247
325
|
|
248
|
-
# scope :active, -> { where(status: 0) }
|
249
|
-
# scope :not_active, -> { where.not(status: 0) }
|
250
326
|
if scopes
|
327
|
+
# scope :active, -> { where(status: 0) }
|
251
328
|
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
252
329
|
klass.scope value_method_name, -> { where(name => value) }
|
253
330
|
|
331
|
+
# scope :not_active, -> { where.not(status: 0) }
|
254
332
|
klass.send(:detect_enum_conflict!, name, "not_#{value_method_name}", true)
|
255
333
|
klass.scope "not_#{value_method_name}", -> { where.not(name => value) }
|
256
334
|
end
|
@@ -267,15 +345,36 @@ module ActiveRecord
|
|
267
345
|
end
|
268
346
|
|
269
347
|
def assert_valid_enum_definition_values(values)
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
348
|
+
case values
|
349
|
+
when Hash
|
350
|
+
if values.empty?
|
351
|
+
raise ArgumentError, "Enum values #{values} must not be empty."
|
352
|
+
end
|
353
|
+
|
354
|
+
if values.keys.any?(&:blank?)
|
355
|
+
raise ArgumentError, "Enum values #{values} must not contain a blank name."
|
356
|
+
end
|
357
|
+
when Array
|
358
|
+
if values.empty?
|
359
|
+
raise ArgumentError, "Enum values #{values} must not be empty."
|
360
|
+
end
|
361
|
+
|
362
|
+
unless values.all?(Symbol) || values.all?(String)
|
363
|
+
raise ArgumentError, "Enum values #{values} must only contain symbols or strings."
|
364
|
+
end
|
365
|
+
|
366
|
+
if values.any?(&:blank?)
|
367
|
+
raise ArgumentError, "Enum values #{values} must not contain a blank name."
|
368
|
+
end
|
369
|
+
else
|
370
|
+
raise ArgumentError, "Enum values #{values} must be either a non-empty hash or an array."
|
275
371
|
end
|
372
|
+
end
|
276
373
|
|
277
|
-
|
278
|
-
|
374
|
+
def assert_valid_enum_options(options)
|
375
|
+
invalid_keys = options.keys & %i[_prefix _suffix _scopes _default _instance_methods]
|
376
|
+
unless invalid_keys.empty?
|
377
|
+
raise ArgumentError, "invalid option(s): #{invalid_keys.map(&:inspect).join(", ")}. Valid options are: :prefix, :suffix, :scopes, :default, :instance_methods, and :validate."
|
279
378
|
end
|
280
379
|
end
|
281
380
|
|
@@ -290,6 +389,8 @@ module ActiveRecord
|
|
290
389
|
raise_conflict_error(enum_name, method_name, type: "class")
|
291
390
|
elsif klass_method && method_defined_within?(method_name, Relation)
|
292
391
|
raise_conflict_error(enum_name, method_name, type: "class", source: Relation.name)
|
392
|
+
elsif klass_method && method_name.to_sym == :id
|
393
|
+
raise_conflict_error(enum_name, method_name)
|
293
394
|
elsif !klass_method && dangerous_attribute_method?(method_name)
|
294
395
|
raise_conflict_error(enum_name, method_name)
|
295
396
|
elsif !klass_method && method_defined_within?(method_name, _enum_methods_module, Module)
|