activerecord 6.1.3.2 → 7.0.0.alpha2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +734 -1058
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +35 -7
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +16 -6
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +24 -25
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/preloader/association.rb +161 -49
- data/lib/active_record/associations/preloader/batch.rb +51 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +37 -11
- data/lib/active_record/associations/preloader.rb +46 -110
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +76 -81
- data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +41 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +66 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +6 -9
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +3 -18
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +11 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -7
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -18
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -9
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
- data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -69
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -21
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +1 -3
- data/lib/active_record/connection_adapters/pool_manager.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
- data/lib/active_record/connection_adapters/schema_cache.rb +35 -4
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -17
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +8 -5
- data/lib/active_record/connection_handling.rb +20 -38
- data/lib/active_record/core.rb +129 -117
- data/lib/active_record/database_configurations/database_config.rb +12 -0
- data/lib/active_record/database_configurations/hash_config.rb +27 -1
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +18 -9
- data/lib/active_record/delegated_type.rb +33 -11
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +80 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +44 -46
- data/lib/active_record/errors.rb +66 -3
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +40 -5
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +16 -11
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +39 -6
- data/lib/active_record/integration.rb +1 -1
- data/lib/active_record/internal_metadata.rb +3 -5
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/log_subscriber.rb +6 -2
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +83 -1
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +109 -79
- data/lib/active_record/model_schema.rb +46 -32
- data/lib/active_record/nested_attributes.rb +3 -3
- data/lib/active_record/no_touching.rb +2 -2
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +134 -45
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +203 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +117 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +83 -58
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +45 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +42 -25
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +32 -23
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +233 -50
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +22 -15
- data/lib/active_record/relation.rb +170 -87
- data/lib/active_record/result.rb +17 -2
- data/lib/active_record/runtime_registry.rb +2 -4
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +3 -3
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/default.rb +62 -15
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +40 -22
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +107 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +45 -4
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +1 -1
- data/lib/active_record.rb +170 -2
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/composite.rb +3 -3
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +18 -22
- data/lib/arel/delete_manager.rb +2 -4
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +8 -13
- data/lib/arel/nodes/homogeneous_in.rb +4 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +3 -2
- data/lib/arel/predications.rb +3 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +2 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +6 -1
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +44 -3
- data/lib/arel.rb +1 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- metadata +55 -16
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module"
|
4
|
+
require "active_support/core_ext/array"
|
5
|
+
|
6
|
+
module ActiveRecord
|
7
|
+
module Encryption
|
8
|
+
extend ActiveSupport::Autoload
|
9
|
+
|
10
|
+
eager_autoload do
|
11
|
+
autoload :Cipher
|
12
|
+
autoload :Config
|
13
|
+
autoload :Configurable
|
14
|
+
autoload :Context
|
15
|
+
autoload :Contexts
|
16
|
+
autoload :DerivedSecretKeyProvider
|
17
|
+
autoload :EncryptableRecord
|
18
|
+
autoload :EncryptedAttributeType
|
19
|
+
autoload :EncryptedFixtures
|
20
|
+
autoload :EncryptingOnlyEncryptor
|
21
|
+
autoload :DeterministicKeyProvider
|
22
|
+
autoload :Encryptor
|
23
|
+
autoload :EnvelopeEncryptionKeyProvider
|
24
|
+
autoload :Errors
|
25
|
+
autoload :ExtendedDeterministicQueries
|
26
|
+
autoload :ExtendedDeterministicUniquenessValidator
|
27
|
+
autoload :Key
|
28
|
+
autoload :KeyGenerator
|
29
|
+
autoload :KeyProvider
|
30
|
+
autoload :Message
|
31
|
+
autoload :MessageSerializer
|
32
|
+
autoload :NullEncryptor
|
33
|
+
autoload :Properties
|
34
|
+
autoload :ReadOnlyNullEncryptor
|
35
|
+
autoload :Scheme
|
36
|
+
end
|
37
|
+
|
38
|
+
class Cipher
|
39
|
+
extend ActiveSupport::Autoload
|
40
|
+
|
41
|
+
eager_autoload do
|
42
|
+
autoload :Aes256Gcm
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
include Configurable
|
47
|
+
include Contexts
|
48
|
+
|
49
|
+
def self.eager_load!
|
50
|
+
super
|
51
|
+
|
52
|
+
Cipher.eager_load!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/active_record/enum.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/hash/slice"
|
3
4
|
require "active_support/core_ext/object/deep_dup"
|
4
5
|
|
5
6
|
module ActiveRecord
|
@@ -7,7 +8,7 @@ module ActiveRecord
|
|
7
8
|
# but can be queried by name. Example:
|
8
9
|
#
|
9
10
|
# class Conversation < ActiveRecord::Base
|
10
|
-
# enum status
|
11
|
+
# enum :status, [ :active, :archived ]
|
11
12
|
# end
|
12
13
|
#
|
13
14
|
# # conversation.update! status: 0
|
@@ -41,16 +42,16 @@ module ActiveRecord
|
|
41
42
|
# Conversation.where(status: [:active, :archived])
|
42
43
|
# Conversation.where.not(status: :active)
|
43
44
|
#
|
44
|
-
# Defining scopes can be disabled by setting +:
|
45
|
+
# Defining scopes can be disabled by setting +:scopes+ to +false+.
|
45
46
|
#
|
46
47
|
# class Conversation < ActiveRecord::Base
|
47
|
-
# enum status
|
48
|
+
# enum :status, [ :active, :archived ], scopes: false
|
48
49
|
# end
|
49
50
|
#
|
50
|
-
# You can set the default enum value by setting +:
|
51
|
+
# You can set the default enum value by setting +:default+, like:
|
51
52
|
#
|
52
53
|
# class Conversation < ActiveRecord::Base
|
53
|
-
# enum status
|
54
|
+
# enum :status, [ :active, :archived ], default: :active
|
54
55
|
# end
|
55
56
|
#
|
56
57
|
# conversation = Conversation.new
|
@@ -60,7 +61,7 @@ module ActiveRecord
|
|
60
61
|
# database integer with a hash:
|
61
62
|
#
|
62
63
|
# class Conversation < ActiveRecord::Base
|
63
|
-
# enum status
|
64
|
+
# enum :status, active: 0, archived: 1
|
64
65
|
# end
|
65
66
|
#
|
66
67
|
# Note that when an array is used, the implicit mapping from the values to database
|
@@ -85,14 +86,14 @@ module ActiveRecord
|
|
85
86
|
#
|
86
87
|
# Conversation.where("status <> ?", Conversation.statuses[:archived])
|
87
88
|
#
|
88
|
-
# You can use the +:
|
89
|
+
# You can use the +:prefix+ or +:suffix+ options when you need to define
|
89
90
|
# multiple enums with same values. If the passed value is +true+, the methods
|
90
91
|
# are prefixed/suffixed with the name of the enum. It is also possible to
|
91
92
|
# supply a custom value:
|
92
93
|
#
|
93
94
|
# class Conversation < ActiveRecord::Base
|
94
|
-
# enum status
|
95
|
-
# enum comments_status
|
95
|
+
# enum :status, [ :active, :archived ], suffix: true
|
96
|
+
# enum :comments_status, [ :active, :inactive ], prefix: :comments
|
96
97
|
# end
|
97
98
|
#
|
98
99
|
# With the above example, the bang and predicate methods along with the
|
@@ -103,7 +104,6 @@ module ActiveRecord
|
|
103
104
|
#
|
104
105
|
# conversation.comments_inactive!
|
105
106
|
# conversation.comments_active? # => false
|
106
|
-
|
107
107
|
module Enum
|
108
108
|
def self.extended(base) # :nodoc:
|
109
109
|
base.class_attribute(:defined_enums, instance_writer: false, default: {})
|
@@ -128,10 +128,8 @@ module ActiveRecord
|
|
128
128
|
value.to_s
|
129
129
|
elsif mapping.has_value?(value)
|
130
130
|
mapping.key(value)
|
131
|
-
elsif value.blank?
|
132
|
-
nil
|
133
131
|
else
|
134
|
-
|
132
|
+
value.presence
|
135
133
|
end
|
136
134
|
end
|
137
135
|
|
@@ -139,33 +137,40 @@ module ActiveRecord
|
|
139
137
|
mapping.key(subtype.deserialize(value))
|
140
138
|
end
|
141
139
|
|
142
|
-
def
|
143
|
-
(
|
140
|
+
def serialize(value)
|
141
|
+
subtype.serialize(mapping.fetch(value, value))
|
144
142
|
end
|
145
143
|
|
146
|
-
def
|
147
|
-
mapping.fetch(value, value)
|
144
|
+
def serializable?(value, &block)
|
145
|
+
subtype.serializable?(mapping.fetch(value, value), &block)
|
148
146
|
end
|
149
147
|
|
150
148
|
def assert_valid_value(value)
|
151
|
-
unless
|
149
|
+
unless value.blank? || mapping.has_key?(value) || mapping.has_value?(value)
|
152
150
|
raise ArgumentError, "'#{value}' is not a valid #{name}"
|
153
151
|
end
|
154
152
|
end
|
155
153
|
|
154
|
+
attr_reader :subtype
|
155
|
+
|
156
156
|
private
|
157
|
-
attr_reader :name, :mapping
|
157
|
+
attr_reader :name, :mapping
|
158
158
|
end
|
159
159
|
|
160
|
-
def enum(
|
161
|
-
|
162
|
-
|
163
|
-
|
160
|
+
def enum(name = nil, values = nil, **options)
|
161
|
+
if name
|
162
|
+
values, options = options, {} unless values
|
163
|
+
return _enum(name, values, **options)
|
164
|
+
end
|
164
165
|
|
165
|
-
|
166
|
-
|
166
|
+
definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default)
|
167
|
+
options.transform_keys! { |key| :"#{key[1..-1]}" }
|
167
168
|
|
168
|
-
definitions.each
|
169
|
+
definitions.each { |name, values| _enum(name, values, **options) }
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
def _enum(name, values, prefix: nil, suffix: nil, scopes: true, **options)
|
169
174
|
assert_valid_enum_definition_values(values)
|
170
175
|
# statuses = { }
|
171
176
|
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
@@ -179,24 +184,19 @@ module ActiveRecord
|
|
179
184
|
detect_enum_conflict!(name, name)
|
180
185
|
detect_enum_conflict!(name, "#{name}=")
|
181
186
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
EnumType.new(attr, enum_values, subtype)
|
187
|
+
attribute(name, **options) do |subtype|
|
188
|
+
subtype = subtype.subtype if EnumType === subtype
|
189
|
+
EnumType.new(name, enum_values, subtype)
|
186
190
|
end
|
187
191
|
|
188
192
|
value_method_names = []
|
189
193
|
_enum_methods_module.module_eval do
|
190
|
-
prefix = if
|
191
|
-
"#{name}_"
|
192
|
-
elsif enum_prefix
|
193
|
-
"#{enum_prefix}_"
|
194
|
+
prefix = if prefix
|
195
|
+
prefix == true ? "#{name}_" : "#{prefix}_"
|
194
196
|
end
|
195
197
|
|
196
|
-
suffix = if
|
197
|
-
"_#{name}"
|
198
|
-
elsif enum_suffix
|
199
|
-
"_#{enum_suffix}"
|
198
|
+
suffix = if suffix
|
199
|
+
suffix == true ? "_#{name}" : "_#{suffix}"
|
200
200
|
end
|
201
201
|
|
202
202
|
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
|
@@ -206,23 +206,21 @@ module ActiveRecord
|
|
206
206
|
|
207
207
|
value_method_name = "#{prefix}#{label}#{suffix}"
|
208
208
|
value_method_names << value_method_name
|
209
|
-
define_enum_methods(name, value_method_name, value,
|
209
|
+
define_enum_methods(name, value_method_name, value, scopes)
|
210
210
|
|
211
211
|
method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
|
212
212
|
value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
|
213
213
|
|
214
214
|
if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
|
215
215
|
value_method_names << value_method_alias
|
216
|
-
define_enum_methods(name, value_method_alias, value,
|
216
|
+
define_enum_methods(name, value_method_alias, value, scopes)
|
217
217
|
end
|
218
218
|
end
|
219
219
|
end
|
220
|
-
detect_negative_enum_conditions!(value_method_names) if
|
220
|
+
detect_negative_enum_conditions!(value_method_names) if scopes
|
221
221
|
enum_values.freeze
|
222
222
|
end
|
223
|
-
end
|
224
223
|
|
225
|
-
private
|
226
224
|
class EnumMethods < Module # :nodoc:
|
227
225
|
def initialize(klass)
|
228
226
|
@klass = klass
|
@@ -231,7 +229,7 @@ module ActiveRecord
|
|
231
229
|
private
|
232
230
|
attr_reader :klass
|
233
231
|
|
234
|
-
def define_enum_methods(name, value_method_name, value,
|
232
|
+
def define_enum_methods(name, value_method_name, value, scopes)
|
235
233
|
# def active?() status_for_database == 0 end
|
236
234
|
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
|
237
235
|
define_method("#{value_method_name}?") { public_send(:"#{name}_for_database") == value }
|
@@ -242,7 +240,7 @@ module ActiveRecord
|
|
242
240
|
|
243
241
|
# scope :active, -> { where(status: 0) }
|
244
242
|
# scope :not_active, -> { where.not(status: 0) }
|
245
|
-
if
|
243
|
+
if scopes
|
246
244
|
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
247
245
|
klass.scope value_method_name, -> { where(name => value) }
|
248
246
|
|
@@ -262,7 +260,7 @@ module ActiveRecord
|
|
262
260
|
end
|
263
261
|
|
264
262
|
def assert_valid_enum_definition_values(values)
|
265
|
-
unless values.is_a?(Hash) || values.all?
|
263
|
+
unless values.is_a?(Hash) || values.all?(Symbol) || values.all?(String)
|
266
264
|
error_message = <<~MSG
|
267
265
|
Enum values #{values} must be either a hash, an array of symbols, or an array of strings.
|
268
266
|
MSG
|
data/lib/active_record/errors.rb
CHANGED
@@ -63,6 +63,30 @@ module ActiveRecord
|
|
63
63
|
class ConnectionTimeoutError < ConnectionNotEstablished
|
64
64
|
end
|
65
65
|
|
66
|
+
# Raised when connection to the database could not been established because it was not
|
67
|
+
# able to connect to the host or when the authorization failed.
|
68
|
+
class DatabaseConnectionError < ConnectionNotEstablished
|
69
|
+
def initialize(message = nil)
|
70
|
+
super(message || "Database connection error")
|
71
|
+
end
|
72
|
+
|
73
|
+
class << self
|
74
|
+
def hostname_error(hostname)
|
75
|
+
DatabaseConnectionError.new(<<~MSG)
|
76
|
+
There is an issue connecting with your hostname: #{hostname}.\n
|
77
|
+
Please check your database configuration and ensure there is a valid connection to your database.
|
78
|
+
MSG
|
79
|
+
end
|
80
|
+
|
81
|
+
def username_error(username)
|
82
|
+
DatabaseConnectionError.new(<<~MSG)
|
83
|
+
There is an issue connecting to your database with your username/password, username: #{username}.\n
|
84
|
+
Please check your database configuration to ensure the username/password are valid.
|
85
|
+
MSG
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
66
90
|
# Raised when a pool was unable to get ahold of all its connections
|
67
91
|
# to perform a "group" action such as
|
68
92
|
# {ActiveRecord::Base.connection_pool.disconnect!}[rdoc-ref:ConnectionAdapters::ConnectionPool#disconnect!]
|
@@ -100,7 +124,7 @@ module ActiveRecord
|
|
100
124
|
end
|
101
125
|
|
102
126
|
# Raised by {ActiveRecord::Base#destroy!}[rdoc-ref:Persistence#destroy!]
|
103
|
-
# when a call to {#destroy}[rdoc-ref:Persistence#destroy
|
127
|
+
# when a call to {#destroy}[rdoc-ref:Persistence#destroy]
|
104
128
|
# would return false.
|
105
129
|
#
|
106
130
|
# begin
|
@@ -118,6 +142,16 @@ module ActiveRecord
|
|
118
142
|
end
|
119
143
|
end
|
120
144
|
|
145
|
+
# Raised when Active Record finds multiple records but only expected one.
|
146
|
+
class SoleRecordExceeded < ActiveRecordError
|
147
|
+
attr_reader :record
|
148
|
+
|
149
|
+
def initialize(record = nil)
|
150
|
+
@record = record
|
151
|
+
super "Wanted only one #{record&.name || "record"}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
121
155
|
# Superclass for all database execution errors.
|
122
156
|
#
|
123
157
|
# Wraps the underlying database error as +cause+.
|
@@ -202,6 +236,30 @@ module ActiveRecord
|
|
202
236
|
|
203
237
|
# Raised when a given database does not exist.
|
204
238
|
class NoDatabaseError < StatementInvalid
|
239
|
+
include ActiveSupport::ActionableError
|
240
|
+
|
241
|
+
action "Create database" do
|
242
|
+
ActiveRecord::Tasks::DatabaseTasks.create_current
|
243
|
+
end
|
244
|
+
|
245
|
+
def initialize(message = nil)
|
246
|
+
super(message || "Database not found")
|
247
|
+
end
|
248
|
+
|
249
|
+
class << self
|
250
|
+
def db_error(db_name)
|
251
|
+
NoDatabaseError.new(<<~MSG)
|
252
|
+
We could not find your database: #{db_name}. Which can be found in the database configuration file located at config/database.yml.
|
253
|
+
|
254
|
+
To resolve this issue:
|
255
|
+
|
256
|
+
- Did you create the database for this app, or delete it? You may need to create your database.
|
257
|
+
- Has the database name changed? Check your database.yml config has the correct database name.
|
258
|
+
|
259
|
+
To create your database, run:\n\n bin/rails db:create
|
260
|
+
MSG
|
261
|
+
end
|
262
|
+
end
|
205
263
|
end
|
206
264
|
|
207
265
|
# Raised when creating a database if it exists.
|
@@ -363,6 +421,11 @@ module ActiveRecord
|
|
363
421
|
class TransactionRollbackError < StatementInvalid
|
364
422
|
end
|
365
423
|
|
424
|
+
# AsynchronousQueryInsideTransactionError will be raised when attempting
|
425
|
+
# to perform an asynchronous query from inside a transaction
|
426
|
+
class AsynchronousQueryInsideTransactionError < ActiveRecordError
|
427
|
+
end
|
428
|
+
|
366
429
|
# SerializationFailure will be raised when a transaction is rolled
|
367
430
|
# back by the database due to a serialization failure.
|
368
431
|
class SerializationFailure < TransactionRollbackError
|
@@ -409,12 +472,12 @@ module ActiveRecord
|
|
409
472
|
#
|
410
473
|
# For example, the following code would raise this exception:
|
411
474
|
#
|
412
|
-
# Post.order("
|
475
|
+
# Post.order("REPLACE(title, 'misc', 'zzzz') asc").pluck(:id)
|
413
476
|
#
|
414
477
|
# The desired result can be accomplished by wrapping the known-safe string
|
415
478
|
# in Arel.sql:
|
416
479
|
#
|
417
|
-
# Post.order(Arel.sql("
|
480
|
+
# Post.order(Arel.sql("REPLACE(title, 'misc', 'zzzz') asc")).pluck(:id)
|
418
481
|
#
|
419
482
|
# Again, such a workaround should *not* be used when passing user-provided
|
420
483
|
# values, such as request parameters or model attributes to query methods.
|
@@ -41,7 +41,7 @@ module ActiveRecord
|
|
41
41
|
@config_row ||= begin
|
42
42
|
row = raw_rows.find { |fixture_name, _| fixture_name == "_fixture" }
|
43
43
|
if row
|
44
|
-
row.last
|
44
|
+
validate_config_row(row.last)
|
45
45
|
else
|
46
46
|
{ 'model_class': nil, 'ignore': nil }
|
47
47
|
end
|
@@ -58,6 +58,20 @@ module ActiveRecord
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
def validate_config_row(data)
|
62
|
+
unless Hash === data
|
63
|
+
raise Fixture::FormatError, "Invalid `_fixture` section: `_fixture` must be a hash: #{@file}"
|
64
|
+
end
|
65
|
+
|
66
|
+
begin
|
67
|
+
data.assert_valid_keys("model_class", "ignore")
|
68
|
+
rescue ArgumentError => error
|
69
|
+
raise Fixture::FormatError, "Invalid `_fixture` section: #{error.message}: #{@file}"
|
70
|
+
end
|
71
|
+
|
72
|
+
data
|
73
|
+
end
|
74
|
+
|
61
75
|
# Validate our unmarshalled data.
|
62
76
|
def validate(data)
|
63
77
|
unless Hash === data || YAML::Omap === data
|
@@ -33,6 +33,33 @@ module ActiveRecord
|
|
33
33
|
def join_table
|
34
34
|
@association.through_reflection.table_name
|
35
35
|
end
|
36
|
+
|
37
|
+
def timestamp_column_names
|
38
|
+
@association.through_reflection.klass.all_timestamp_attributes_in_model
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class PrimaryKeyError < StandardError # :nodoc:
|
43
|
+
def initialize(label, association, value)
|
44
|
+
super(<<~MSG)
|
45
|
+
Unable to set #{association.name} to #{value} because the association has a
|
46
|
+
custom primary key (#{association.join_primary_key}) that does not match the
|
47
|
+
associated table's primary key (#{association.klass.primary_key}).
|
48
|
+
|
49
|
+
To fix this, change your fixture from
|
50
|
+
|
51
|
+
#{label}:
|
52
|
+
#{association.name}: #{value}
|
53
|
+
|
54
|
+
to
|
55
|
+
|
56
|
+
#{label}:
|
57
|
+
#{association.foreign_key}: **value**
|
58
|
+
|
59
|
+
where **value** is the #{association.join_primary_key} value for the
|
60
|
+
associated #{association.klass.name} record.
|
61
|
+
MSG
|
62
|
+
end
|
36
63
|
end
|
37
64
|
|
38
65
|
def initialize(fixture, table_rows:, label:, now:)
|
@@ -115,9 +142,13 @@ module ActiveRecord
|
|
115
142
|
fk_name = association.join_foreign_key
|
116
143
|
|
117
144
|
if association.name.to_s != fk_name && value = @row.delete(association.name.to_s)
|
118
|
-
if association.polymorphic?
|
119
|
-
|
120
|
-
|
145
|
+
if association.polymorphic?
|
146
|
+
if value.sub!(/\s*\(([^)]*)\)\s*$/, "")
|
147
|
+
# support polymorphic belongs_to as "label (Type)"
|
148
|
+
@row[association.join_foreign_type] = $1
|
149
|
+
end
|
150
|
+
elsif association.join_primary_key != association.klass.primary_key
|
151
|
+
raise PrimaryKeyError.new(@label, association, value)
|
121
152
|
end
|
122
153
|
|
123
154
|
fk_type = reflection_class.type_for_attribute(fk_name).type
|
@@ -141,8 +172,12 @@ module ActiveRecord
|
|
141
172
|
|
142
173
|
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
|
143
174
|
joins = targets.map do |target|
|
144
|
-
{ lhs_key => @row[model_metadata.primary_key_name],
|
145
|
-
|
175
|
+
join = { lhs_key => @row[model_metadata.primary_key_name],
|
176
|
+
rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
|
177
|
+
association.timestamp_column_names.each do |col|
|
178
|
+
join[col] = @now
|
179
|
+
end
|
180
|
+
join
|
146
181
|
end
|
147
182
|
@table_rows.tables[table_name].concat(joins)
|
148
183
|
end
|