activerecord 7.2.3 → 8.0.0.beta1
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.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +192 -1261
- data/README.rdoc +2 -2
- data/lib/active_record/associations/alias_tracker.rb +4 -6
- data/lib/active_record/associations/association.rb +25 -5
- data/lib/active_record/associations/belongs_to_association.rb +2 -18
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/collection_association.rb +4 -4
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +4 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +50 -32
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods.rb +19 -24
- data/lib/active_record/attributes.rb +26 -37
- data/lib/active_record/autosave_association.rb +81 -49
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -75
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +14 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -6
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +27 -9
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +27 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +28 -58
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -15
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -16
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +12 -14
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +51 -9
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +44 -101
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -13
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +60 -22
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -18
- data/lib/active_record/connection_handling.rb +29 -11
- data/lib/active_record/core.rb +15 -60
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -3
- data/lib/active_record/delegated_type.rb +18 -18
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +5 -5
- data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
- data/lib/active_record/encryption/encryptor.rb +35 -29
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/enum.rb +12 -13
- data/lib/active_record/errors.rb +16 -8
- data/lib/active_record/fixture_set/table_row.rb +2 -19
- data/lib/active_record/fixtures.rb +0 -1
- data/lib/active_record/future_result.rb +14 -10
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/insert_all.rb +1 -1
- data/lib/active_record/marshalling.rb +1 -4
- data/lib/active_record/migration/command_recorder.rb +22 -5
- data/lib/active_record/migration/compatibility.rb +5 -2
- data/lib/active_record/migration.rb +36 -35
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/nested_attributes.rb +4 -6
- data/lib/active_record/persistence.rb +128 -130
- data/lib/active_record/query_cache.rb +5 -4
- data/lib/active_record/query_logs.rb +98 -44
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +10 -10
- data/lib/active_record/railtie.rb +5 -6
- data/lib/active_record/railties/databases.rake +1 -2
- data/lib/active_record/reflection.rb +9 -7
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +132 -72
- data/lib/active_record/relation/calculations.rb +55 -55
- data/lib/active_record/relation/delegation.rb +25 -14
- data/lib/active_record/relation/finder_methods.rb +31 -32
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +0 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +5 -0
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +90 -91
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +2 -8
- data/lib/active_record/relation.rb +77 -76
- data/lib/active_record/result.rb +68 -7
- data/lib/active_record/sanitization.rb +7 -6
- data/lib/active_record/schema_dumper.rb +16 -29
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +6 -7
- data/lib/active_record/statement_cache.rb +12 -12
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +24 -15
- data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +0 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
- data/lib/active_record/test_fixtures.rb +12 -0
- data/lib/active_record/testing/query_assertions.rb +2 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transactions.rb +1 -3
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +16 -1
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/crud.rb +0 -2
- data/lib/arel/delete_manager.rb +0 -5
- data/lib/arel/nodes/delete_statement.rb +2 -4
- data/lib/arel/nodes/update_statement.rb +2 -4
- data/lib/arel/select_manager.rb +2 -6
- data/lib/arel/update_manager.rb +0 -5
- data/lib/arel/visitors/dot.rb +0 -2
- data/lib/arel/visitors/sqlite.rb +0 -25
- data/lib/arel/visitors/to_sql.rb +1 -3
- metadata +14 -11
|
@@ -16,7 +16,7 @@ module ActiveRecord
|
|
|
16
16
|
class_methods do
|
|
17
17
|
# Encrypts the +name+ attribute.
|
|
18
18
|
#
|
|
19
|
-
#
|
|
19
|
+
# === Options
|
|
20
20
|
#
|
|
21
21
|
# * <tt>:key_provider</tt> - A key provider to provide encryption and decryption keys. Defaults to
|
|
22
22
|
# +ActiveRecord::Encryption.key_provider+.
|
|
@@ -46,11 +46,11 @@ module ActiveRecord
|
|
|
46
46
|
# * <tt>:previous</tt> - List of previous encryption schemes. When provided, they will be used in order when trying to read
|
|
47
47
|
# the attribute. Each entry of the list can contain the properties supported by #encrypts. Also, when deterministic
|
|
48
48
|
# encryption is used, they will be used to generate additional ciphertexts to check in the queries.
|
|
49
|
-
def encrypts(*names, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)
|
|
49
|
+
def encrypts(*names, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)
|
|
50
50
|
self.encrypted_attributes ||= Set.new # not using :default because the instance would be shared across classes
|
|
51
51
|
|
|
52
52
|
names.each do |name|
|
|
53
|
-
encrypt_attribute name, key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, downcase: downcase, ignore_case: ignore_case, previous: previous, **context_properties
|
|
53
|
+
encrypt_attribute name, key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, downcase: downcase, ignore_case: ignore_case, previous: previous, compress: compress, compressor: compressor, **context_properties
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
@@ -81,12 +81,12 @@ module ActiveRecord
|
|
|
81
81
|
end
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
-
def encrypt_attribute(name, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)
|
|
84
|
+
def encrypt_attribute(name, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)
|
|
85
85
|
encrypted_attributes << name.to_sym
|
|
86
86
|
|
|
87
87
|
decorate_attributes([name]) do |name, cast_type|
|
|
88
88
|
scheme = scheme_for key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, \
|
|
89
|
-
downcase: downcase, ignore_case: ignore_case, previous: previous, **context_properties
|
|
89
|
+
downcase: downcase, ignore_case: ignore_case, previous: previous, compress: compress, compressor: compressor, **context_properties
|
|
90
90
|
|
|
91
91
|
ActiveRecord::Encryption::EncryptedAttributeType.new(scheme: scheme, cast_type: cast_type, default: columns_hash[name.to_s]&.default)
|
|
92
92
|
end
|
|
@@ -15,7 +15,7 @@ module ActiveRecord
|
|
|
15
15
|
delegate :key_provider, :downcase?, :deterministic?, :previous_schemes, :with_context, :fixed?, to: :scheme
|
|
16
16
|
delegate :accessor, :type, to: :cast_type
|
|
17
17
|
|
|
18
|
-
#
|
|
18
|
+
# === Options
|
|
19
19
|
#
|
|
20
20
|
# * <tt>:scheme</tt> - A +Scheme+ with the encryption properties for this attribute.
|
|
21
21
|
# * <tt>:cast_type</tt> - A type that will be used to serialize (before encrypting) and deserialize
|
|
@@ -100,7 +100,7 @@ module ActiveRecord
|
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
def decrypt(value)
|
|
103
|
-
text_to_database_type decrypt_as_text(value)
|
|
103
|
+
text_to_database_type decrypt_as_text(database_type_to_text(value))
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
def try_to_deserialize_with_previous_encrypted_types(value)
|
|
@@ -170,6 +170,15 @@ module ActiveRecord
|
|
|
170
170
|
value
|
|
171
171
|
end
|
|
172
172
|
end
|
|
173
|
+
|
|
174
|
+
def database_type_to_text(value)
|
|
175
|
+
if value && cast_type.binary?
|
|
176
|
+
binary_cast_type = cast_type.serialized? ? cast_type.subtype : cast_type
|
|
177
|
+
binary_cast_type.deserialize(value)
|
|
178
|
+
else
|
|
179
|
+
value
|
|
180
|
+
end
|
|
181
|
+
end
|
|
173
182
|
end
|
|
174
183
|
end
|
|
175
184
|
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "openssl"
|
|
4
|
-
require "zlib"
|
|
5
4
|
require "active_support/core_ext/numeric"
|
|
6
5
|
|
|
7
6
|
module ActiveRecord
|
|
@@ -12,34 +11,41 @@ module ActiveRecord
|
|
|
12
11
|
# It interacts with a KeyProvider for getting the keys, and delegate to
|
|
13
12
|
# ActiveRecord::Encryption::Cipher the actual encryption algorithm.
|
|
14
13
|
class Encryptor
|
|
15
|
-
#
|
|
14
|
+
# The compressor to use for compressing the payload
|
|
15
|
+
attr_reader :compressor
|
|
16
|
+
|
|
17
|
+
# === Options
|
|
16
18
|
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
|
|
19
|
+
# * <tt>:compress</tt> - Boolean indicating whether records should be compressed before encryption.
|
|
20
|
+
# Defaults to +true+.
|
|
21
|
+
# * <tt>:compressor</tt> - The compressor to use.
|
|
22
|
+
# 1. If compressor is provided, it will be used.
|
|
23
|
+
# 2. If not, it will use ActiveRecord::Encryption.config.compressor which default value is +Zlib+.
|
|
24
|
+
# If you want to use a custom compressor, it must respond to +deflate+ and +inflate+.
|
|
25
|
+
def initialize(compress: true, compressor: nil)
|
|
21
26
|
@compress = compress
|
|
27
|
+
@compressor = compressor || ActiveRecord::Encryption.config.compressor
|
|
22
28
|
end
|
|
23
29
|
|
|
24
|
-
# Encrypts +clean_text+ and returns the encrypted result
|
|
30
|
+
# Encrypts +clean_text+ and returns the encrypted result
|
|
25
31
|
#
|
|
26
32
|
# Internally, it will:
|
|
27
33
|
#
|
|
28
|
-
# 1. Create a new ActiveRecord::Encryption::Message
|
|
29
|
-
# 2. Compress and encrypt +clean_text+ as the message payload
|
|
30
|
-
# 3. Serialize it with +ActiveRecord::Encryption.message_serializer+
|
|
31
|
-
#
|
|
32
|
-
# 4. Encode the result with
|
|
34
|
+
# 1. Create a new ActiveRecord::Encryption::Message
|
|
35
|
+
# 2. Compress and encrypt +clean_text+ as the message payload
|
|
36
|
+
# 3. Serialize it with +ActiveRecord::Encryption.message_serializer+ (+ActiveRecord::Encryption::SafeMarshal+
|
|
37
|
+
# by default)
|
|
38
|
+
# 4. Encode the result with Base 64
|
|
33
39
|
#
|
|
34
|
-
#
|
|
40
|
+
# === Options
|
|
35
41
|
#
|
|
36
|
-
# [
|
|
42
|
+
# [:key_provider]
|
|
37
43
|
# Key provider to use for the encryption operation. It will default to
|
|
38
44
|
# +ActiveRecord::Encryption.key_provider+ when not provided.
|
|
39
45
|
#
|
|
40
|
-
# [
|
|
46
|
+
# [:cipher_options]
|
|
41
47
|
# Cipher-specific options that will be passed to the Cipher configured in
|
|
42
|
-
# +ActiveRecord::Encryption.cipher
|
|
48
|
+
# +ActiveRecord::Encryption.cipher+
|
|
43
49
|
def encrypt(clear_text, key_provider: default_key_provider, cipher_options: {})
|
|
44
50
|
clear_text = force_encoding_if_needed(clear_text) if cipher_options[:deterministic]
|
|
45
51
|
|
|
@@ -47,17 +53,17 @@ module ActiveRecord
|
|
|
47
53
|
serialize_message build_encrypted_message(clear_text, key_provider: key_provider, cipher_options: cipher_options)
|
|
48
54
|
end
|
|
49
55
|
|
|
50
|
-
# Decrypts an +encrypted_text+ and returns the result as clean text
|
|
56
|
+
# Decrypts an +encrypted_text+ and returns the result as clean text
|
|
51
57
|
#
|
|
52
|
-
#
|
|
58
|
+
# === Options
|
|
53
59
|
#
|
|
54
|
-
# [
|
|
60
|
+
# [:key_provider]
|
|
55
61
|
# Key provider to use for the encryption operation. It will default to
|
|
56
|
-
# +ActiveRecord::Encryption.key_provider+ when not provided
|
|
62
|
+
# +ActiveRecord::Encryption.key_provider+ when not provided
|
|
57
63
|
#
|
|
58
|
-
# [
|
|
64
|
+
# [:cipher_options]
|
|
59
65
|
# Cipher-specific options that will be passed to the Cipher configured in
|
|
60
|
-
# +ActiveRecord::Encryption.cipher
|
|
66
|
+
# +ActiveRecord::Encryption.cipher+
|
|
61
67
|
def decrypt(encrypted_text, key_provider: default_key_provider, cipher_options: {})
|
|
62
68
|
message = deserialize_message(encrypted_text)
|
|
63
69
|
keys = key_provider.decryption_keys(message)
|
|
@@ -67,7 +73,7 @@ module ActiveRecord
|
|
|
67
73
|
raise Errors::Decryption
|
|
68
74
|
end
|
|
69
75
|
|
|
70
|
-
# Returns whether the text is encrypted or not
|
|
76
|
+
# Returns whether the text is encrypted or not
|
|
71
77
|
def encrypted?(text)
|
|
72
78
|
deserialize_message(text)
|
|
73
79
|
true
|
|
@@ -79,6 +85,10 @@ module ActiveRecord
|
|
|
79
85
|
serializer.binary?
|
|
80
86
|
end
|
|
81
87
|
|
|
88
|
+
def compress? # :nodoc:
|
|
89
|
+
@compress
|
|
90
|
+
end
|
|
91
|
+
|
|
82
92
|
private
|
|
83
93
|
DECRYPT_ERRORS = [OpenSSL::Cipher::CipherError, Errors::EncryptedContentIntegrity, Errors::Decryption]
|
|
84
94
|
ENCODING_ERRORS = [EncodingError, Errors::Encoding]
|
|
@@ -131,12 +141,8 @@ module ActiveRecord
|
|
|
131
141
|
end
|
|
132
142
|
end
|
|
133
143
|
|
|
134
|
-
def compress?
|
|
135
|
-
@compress
|
|
136
|
-
end
|
|
137
|
-
|
|
138
144
|
def compress(data)
|
|
139
|
-
|
|
145
|
+
@compressor.deflate(data).tap do |compressed_data|
|
|
140
146
|
compressed_data.force_encoding(data.encoding)
|
|
141
147
|
end
|
|
142
148
|
end
|
|
@@ -150,7 +156,7 @@ module ActiveRecord
|
|
|
150
156
|
end
|
|
151
157
|
|
|
152
158
|
def uncompress(data)
|
|
153
|
-
|
|
159
|
+
@compressor.inflate(data).tap do |uncompressed_data|
|
|
154
160
|
uncompressed_data.force_encoding(data.encoding)
|
|
155
161
|
end
|
|
156
162
|
end
|
|
@@ -41,6 +41,8 @@ module ActiveRecord
|
|
|
41
41
|
module EncryptedQuery # :nodoc:
|
|
42
42
|
class << self
|
|
43
43
|
def process_arguments(owner, args, check_for_additional_values)
|
|
44
|
+
owner = owner.model if owner.is_a?(Relation)
|
|
45
|
+
|
|
44
46
|
return args if owner.deterministic_encrypted_attributes&.empty?
|
|
45
47
|
|
|
46
48
|
if args.is_a?(Array) && (options = args.first).is_a?(Hash)
|
|
@@ -102,12 +104,12 @@ module ActiveRecord
|
|
|
102
104
|
end
|
|
103
105
|
|
|
104
106
|
def scope_for_create
|
|
105
|
-
return super unless
|
|
107
|
+
return super unless model.deterministic_encrypted_attributes&.any?
|
|
106
108
|
|
|
107
109
|
scope_attributes = super
|
|
108
110
|
wheres = where_values_hash
|
|
109
111
|
|
|
110
|
-
|
|
112
|
+
model.deterministic_encrypted_attributes.each do |attribute_name|
|
|
111
113
|
attribute_name = attribute_name.to_s
|
|
112
114
|
values = wheres[attribute_name]
|
|
113
115
|
if values.is_a?(Array) && values[1..].all?(AdditionalValue)
|
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
|
11
11
|
attr_accessor :previous_schemes
|
|
12
12
|
|
|
13
13
|
def initialize(key_provider: nil, key: nil, deterministic: nil, support_unencrypted_data: nil, downcase: nil, ignore_case: nil,
|
|
14
|
-
previous_schemes: nil, **context_properties)
|
|
14
|
+
previous_schemes: nil, compress: true, compressor: 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+
|
|
17
17
|
|
|
@@ -24,8 +24,13 @@ module ActiveRecord
|
|
|
24
24
|
@previous_schemes_param = previous_schemes
|
|
25
25
|
@previous_schemes = Array.wrap(previous_schemes)
|
|
26
26
|
@context_properties = context_properties
|
|
27
|
+
@compress = compress
|
|
28
|
+
@compressor = compressor
|
|
27
29
|
|
|
28
30
|
validate_config!
|
|
31
|
+
|
|
32
|
+
@context_properties[:encryptor] = Encryptor.new(compress: @compress) unless @compress
|
|
33
|
+
@context_properties[:encryptor] = Encryptor.new(compressor: compressor) if compressor
|
|
29
34
|
end
|
|
30
35
|
|
|
31
36
|
def ignore_case?
|
|
@@ -78,6 +83,8 @@ module ActiveRecord
|
|
|
78
83
|
def validate_config!
|
|
79
84
|
raise Errors::Configuration, "ignore_case: can only be used with deterministic encryption" if @ignore_case && !@deterministic
|
|
80
85
|
raise Errors::Configuration, "key_provider: and key: can't be used simultaneously" if @key_provider_param && @key
|
|
86
|
+
raise Errors::Configuration, "compressor: can't be used with compress: false" if !@compress && @compressor
|
|
87
|
+
raise Errors::Configuration, "compressor: can't be used with encryptor" if @compressor && @context_properties[:encryptor]
|
|
81
88
|
end
|
|
82
89
|
|
|
83
90
|
def key_provider_from_key
|
data/lib/active_record/enum.rb
CHANGED
|
@@ -119,18 +119,7 @@ module ActiveRecord
|
|
|
119
119
|
# enum :status, [ :active, :archived ], instance_methods: false
|
|
120
120
|
# end
|
|
121
121
|
#
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
# class Conversation < ActiveRecord::Base
|
|
125
|
-
# enum :status, [ :active, :archived ]
|
|
126
|
-
# end
|
|
127
|
-
#
|
|
128
|
-
# conversation = Conversation.new
|
|
129
|
-
#
|
|
130
|
-
# conversation.status = :unknown # 'unknown' is not a valid status (ArgumentError)
|
|
131
|
-
#
|
|
132
|
-
# If, instead, you want the enum value to be validated before saving, use the
|
|
133
|
-
# +:validate+ option:
|
|
122
|
+
# If you want the enum value to be validated before saving, use the option +:validate+:
|
|
134
123
|
#
|
|
135
124
|
# class Conversation < ActiveRecord::Base
|
|
136
125
|
# enum :status, [ :active, :archived ], validate: true
|
|
@@ -147,7 +136,7 @@ module ActiveRecord
|
|
|
147
136
|
# conversation.status = :active
|
|
148
137
|
# conversation.valid? # => true
|
|
149
138
|
#
|
|
150
|
-
#
|
|
139
|
+
# It is also possible to pass additional validation options:
|
|
151
140
|
#
|
|
152
141
|
# class Conversation < ActiveRecord::Base
|
|
153
142
|
# enum :status, [ :active, :archived ], validate: { allow_nil: true }
|
|
@@ -163,6 +152,16 @@ module ActiveRecord
|
|
|
163
152
|
#
|
|
164
153
|
# conversation.status = :active
|
|
165
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)
|
|
166
165
|
module Enum
|
|
167
166
|
def self.extended(base) # :nodoc:
|
|
168
167
|
base.class_attribute(:defined_enums, instance_writer: false, default: {})
|
data/lib/active_record/errors.rb
CHANGED
|
@@ -13,7 +13,7 @@ module ActiveRecord
|
|
|
13
13
|
|
|
14
14
|
# Raised when the single-table inheritance mechanism fails to locate the subclass
|
|
15
15
|
# (for example due to improper usage of column that
|
|
16
|
-
# {ActiveRecord::Base.inheritance_column}[rdoc-ref:ModelSchema
|
|
16
|
+
# {ActiveRecord::Base.inheritance_column}[rdoc-ref:ModelSchema::ClassMethods#inheritance_column]
|
|
17
17
|
# points to).
|
|
18
18
|
class SubclassNotFound < ActiveRecordError
|
|
19
19
|
end
|
|
@@ -84,6 +84,19 @@ module ActiveRecord
|
|
|
84
84
|
class ConnectionTimeoutError < ConnectionNotEstablished
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
+
# Raised when a database connection pool is requested but
|
|
88
|
+
# has not been defined.
|
|
89
|
+
class ConnectionNotDefined < ConnectionNotEstablished
|
|
90
|
+
def initialize(message = nil, connection_name: nil, role: nil, shard: nil)
|
|
91
|
+
super(message)
|
|
92
|
+
@connection_name = connection_name
|
|
93
|
+
@role = role
|
|
94
|
+
@shard = shard
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
attr_reader :connection_name, :role, :shard
|
|
98
|
+
end
|
|
99
|
+
|
|
87
100
|
# Raised when connection to the database could not been established because it was not
|
|
88
101
|
# able to connect to the host or when the authorization failed.
|
|
89
102
|
class DatabaseConnectionError < ConnectionNotEstablished
|
|
@@ -431,7 +444,7 @@ module ActiveRecord
|
|
|
431
444
|
UnknownAttributeError = ActiveModel::UnknownAttributeError
|
|
432
445
|
|
|
433
446
|
# Raised when an error occurred while doing a mass assignment to an attribute through the
|
|
434
|
-
# {ActiveRecord::Base#attributes=}[rdoc-ref:
|
|
447
|
+
# {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
|
|
435
448
|
# The exception has an +attribute+ property that is the name of the offending attribute.
|
|
436
449
|
class AttributeAssignmentError < ActiveRecordError
|
|
437
450
|
attr_reader :exception, :attribute
|
|
@@ -444,7 +457,7 @@ module ActiveRecord
|
|
|
444
457
|
end
|
|
445
458
|
|
|
446
459
|
# Raised when there are multiple errors while doing a mass assignment through the
|
|
447
|
-
# {ActiveRecord::Base#attributes=}[rdoc-ref:
|
|
460
|
+
# {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=]
|
|
448
461
|
# method. The exception has an +errors+ property that contains an array of AttributeAssignmentError
|
|
449
462
|
# objects, each corresponding to the error while assigning to an attribute.
|
|
450
463
|
class MultiparameterAssignmentErrors < ActiveRecordError
|
|
@@ -484,11 +497,6 @@ module ActiveRecord
|
|
|
484
497
|
# relation.limit!(5) # => ActiveRecord::UnmodifiableRelation
|
|
485
498
|
class UnmodifiableRelation < ActiveRecordError
|
|
486
499
|
end
|
|
487
|
-
deprecate_constant(
|
|
488
|
-
:ImmutableRelation,
|
|
489
|
-
"ActiveRecord::UnmodifiableRelation",
|
|
490
|
-
deprecator: ActiveRecord.deprecator
|
|
491
|
-
)
|
|
492
500
|
|
|
493
501
|
# TransactionIsolationError will be raised under the following conditions:
|
|
494
502
|
#
|
|
@@ -193,25 +193,8 @@ module ActiveRecord
|
|
|
193
193
|
|
|
194
194
|
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
|
|
195
195
|
joins = targets.map do |target|
|
|
196
|
-
join = {
|
|
197
|
-
|
|
198
|
-
if rhs_key.is_a?(Array)
|
|
199
|
-
composite_key = ActiveRecord::FixtureSet.composite_identify(target, rhs_key)
|
|
200
|
-
composite_key.each do |column, value|
|
|
201
|
-
join[column] = value
|
|
202
|
-
end
|
|
203
|
-
else
|
|
204
|
-
join[rhs_key] = ActiveRecord::FixtureSet.identify(target, column_type)
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
if lhs_key.is_a?(Array)
|
|
208
|
-
lhs_key.zip(model_metadata.primary_key_name).each do |fkey, pkey|
|
|
209
|
-
join[fkey] = @row[pkey]
|
|
210
|
-
end
|
|
211
|
-
else
|
|
212
|
-
join[lhs_key] = @row[model_metadata.primary_key_name]
|
|
213
|
-
end
|
|
214
|
-
|
|
196
|
+
join = { lhs_key => @row[model_metadata.primary_key_name],
|
|
197
|
+
rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
|
|
215
198
|
association.timestamp_column_names.each do |col|
|
|
216
199
|
join[col] = @now
|
|
217
200
|
end
|
|
@@ -100,17 +100,21 @@ module ActiveRecord
|
|
|
100
100
|
def execute_or_skip
|
|
101
101
|
return unless pending?
|
|
102
102
|
|
|
103
|
-
@
|
|
104
|
-
return unless
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
103
|
+
@session.synchronize do
|
|
104
|
+
return unless pending?
|
|
105
|
+
|
|
106
|
+
@pool.with_connection do |connection|
|
|
107
|
+
return unless @mutex.try_lock
|
|
108
|
+
begin
|
|
109
|
+
if pending?
|
|
110
|
+
@event_buffer = EventBuffer.new(self, @instrumenter)
|
|
111
|
+
connection.with_instrumenter(@event_buffer) do
|
|
112
|
+
execute_query(connection, async: true)
|
|
113
|
+
end
|
|
110
114
|
end
|
|
115
|
+
ensure
|
|
116
|
+
@mutex.unlock
|
|
111
117
|
end
|
|
112
|
-
ensure
|
|
113
|
-
@mutex.unlock
|
|
114
118
|
end
|
|
115
119
|
end
|
|
116
120
|
end
|
|
@@ -163,7 +167,7 @@ module ActiveRecord
|
|
|
163
167
|
end
|
|
164
168
|
|
|
165
169
|
def exec_query(connection, *args, **kwargs)
|
|
166
|
-
connection.
|
|
170
|
+
connection.raw_exec_query(*args, **kwargs)
|
|
167
171
|
end
|
|
168
172
|
|
|
169
173
|
class SelectAll < FutureResult # :nodoc:
|
|
@@ -240,7 +240,7 @@ module ActiveRecord
|
|
|
240
240
|
|
|
241
241
|
values_list = insert_all.map_key_with_value do |key, value|
|
|
242
242
|
next value if Arel::Nodes::SqlLiteral === value
|
|
243
|
-
|
|
243
|
+
types[key].serialize(types[key].cast(value))
|
|
244
244
|
end
|
|
245
245
|
|
|
246
246
|
connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
|
|
@@ -25,10 +25,7 @@ module ActiveRecord
|
|
|
25
25
|
payload = [attributes_for_database, new_record?]
|
|
26
26
|
|
|
27
27
|
cached_associations = self.class.reflect_on_all_associations.select do |reflection|
|
|
28
|
-
|
|
29
|
-
association = association(reflection.name)
|
|
30
|
-
association.loaded? || association.target.present?
|
|
31
|
-
end
|
|
28
|
+
association_cached?(reflection.name) && association(reflection.name).loaded?
|
|
32
29
|
end
|
|
33
30
|
|
|
34
31
|
unless cached_associations.empty?
|
|
@@ -22,10 +22,12 @@ module ActiveRecord
|
|
|
22
22
|
# * change_table_comment (must supply a +:from+ and +:to+ option)
|
|
23
23
|
# * create_enum
|
|
24
24
|
# * create_join_table
|
|
25
|
+
# * create_virtual_table
|
|
25
26
|
# * create_table
|
|
26
27
|
# * disable_extension
|
|
27
28
|
# * drop_enum (must supply a list of values)
|
|
28
29
|
# * drop_join_table
|
|
30
|
+
# * drop_virtual_table (must supply options)
|
|
29
31
|
# * drop_table (must supply a block)
|
|
30
32
|
# * enable_extension
|
|
31
33
|
# * remove_column (must supply a type)
|
|
@@ -55,6 +57,8 @@ module ActiveRecord
|
|
|
55
57
|
:add_exclusion_constraint, :remove_exclusion_constraint,
|
|
56
58
|
:add_unique_constraint, :remove_unique_constraint,
|
|
57
59
|
:create_enum, :drop_enum, :rename_enum, :add_enum_value, :rename_enum_value,
|
|
60
|
+
:create_schema, :drop_schema,
|
|
61
|
+
:create_virtual_table, :drop_virtual_table
|
|
58
62
|
]
|
|
59
63
|
include JoinTable
|
|
60
64
|
|
|
@@ -163,7 +167,9 @@ module ActiveRecord
|
|
|
163
167
|
add_exclusion_constraint: :remove_exclusion_constraint,
|
|
164
168
|
add_unique_constraint: :remove_unique_constraint,
|
|
165
169
|
enable_extension: :disable_extension,
|
|
166
|
-
create_enum: :drop_enum
|
|
170
|
+
create_enum: :drop_enum,
|
|
171
|
+
create_schema: :drop_schema,
|
|
172
|
+
create_virtual_table: :drop_virtual_table
|
|
167
173
|
}.each do |cmd, inv|
|
|
168
174
|
[[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
|
|
169
175
|
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
|
@@ -196,13 +202,18 @@ module ActiveRecord
|
|
|
196
202
|
end
|
|
197
203
|
|
|
198
204
|
def invert_drop_table(args, &block)
|
|
199
|
-
|
|
200
|
-
|
|
205
|
+
options = args.extract_options!
|
|
206
|
+
options.delete(:if_exists)
|
|
207
|
+
|
|
208
|
+
if args.size > 1
|
|
209
|
+
raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given a single table name."
|
|
201
210
|
end
|
|
202
|
-
|
|
211
|
+
|
|
212
|
+
if args.size == 1 && options == {} && block == nil
|
|
203
213
|
raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
|
|
204
214
|
end
|
|
205
|
-
|
|
215
|
+
|
|
216
|
+
super(args.push(options), &block)
|
|
206
217
|
end
|
|
207
218
|
|
|
208
219
|
def invert_rename_table(args)
|
|
@@ -372,6 +383,12 @@ module ActiveRecord
|
|
|
372
383
|
[:rename_enum_value, [type_name, from: options[:to], to: options[:from]]]
|
|
373
384
|
end
|
|
374
385
|
|
|
386
|
+
def invert_drop_virtual_table(args)
|
|
387
|
+
_enum, values = args.dup.tap(&:extract_options!)
|
|
388
|
+
raise ActiveRecord::IrreversibleMigration, "drop_virtual_table is only reversible if given options." unless values
|
|
389
|
+
super
|
|
390
|
+
end
|
|
391
|
+
|
|
375
392
|
def respond_to_missing?(method, _)
|
|
376
393
|
super || delegate.respond_to?(method)
|
|
377
394
|
end
|
|
@@ -21,7 +21,7 @@ module ActiveRecord
|
|
|
21
21
|
# New migration functionality that will never be backward compatible should be added directly to `ActiveRecord::Migration`.
|
|
22
22
|
#
|
|
23
23
|
# There are classes for each prior Rails version. Each class descends from the *next* Rails version, so:
|
|
24
|
-
# 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2
|
|
24
|
+
# 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2 < 8.0
|
|
25
25
|
#
|
|
26
26
|
# If you are introducing new migration functionality that should only apply from Rails 7 onward, then you should
|
|
27
27
|
# find the class that immediately precedes it (6.1), and override the relevant migration methods to undo your changes.
|
|
@@ -29,7 +29,10 @@ module ActiveRecord
|
|
|
29
29
|
# For example, Rails 6 added a default value for the `precision` option on datetime columns. So in this file, the `V5_2`
|
|
30
30
|
# class sets the value of `precision` to `nil` if it's not explicitly provided. This way, the default value will not apply
|
|
31
31
|
# for migrations written for 5.2, but will for migrations written for 6.0.
|
|
32
|
-
|
|
32
|
+
V8_0 = Current
|
|
33
|
+
|
|
34
|
+
class V7_2 < V8_0
|
|
35
|
+
end
|
|
33
36
|
|
|
34
37
|
class V7_1 < V7_2
|
|
35
38
|
end
|