activerecord 7.0.0 → 7.1.0
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 +1607 -1040
- data/MIT-LICENSE +1 -1
- data/README.rdoc +17 -18
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +17 -12
- data/lib/active_record/associations/collection_proxy.rb +22 -12
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +27 -17
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +20 -14
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +345 -219
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +40 -26
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +172 -69
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +110 -28
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +56 -10
- data/lib/active_record/base.rb +10 -5
- data/lib/active_record/callbacks.rb +16 -32
- 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 -34
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +164 -89
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +128 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +52 -8
- 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 +163 -29
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +302 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +504 -106
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +217 -104
- 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 +23 -144
- data/lib/active_record/connection_adapters/mysql/quoting.rb +29 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +72 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -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 +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +41 -8
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +6 -10
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +358 -57
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +343 -181
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +45 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +22 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +41 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +242 -81
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +73 -96
- data/lib/active_record/core.rb +136 -148
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -0
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +9 -4
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/disable_joins_association_relation.rb +1 -1
- 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 +13 -14
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +8 -4
- data/lib/active_record/encryption/derived_secret_key_provider.rb +9 -3
- data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
- data/lib/active_record/encryption/encryptable_record.rb +38 -22
- data/lib/active_record/encryption/encrypted_attribute_type.rb +19 -8
- data/lib/active_record/encryption/encryptor.rb +7 -7
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +3 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +83 -71
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message.rb +1 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +4 -4
- data/lib/active_record/encryption/scheme.rb +20 -23
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +114 -27
- data/lib/active_record/errors.rb +108 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +121 -73
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +55 -8
- data/lib/active_record/integration.rb +10 -10
- data/lib/active_record/internal_metadata.rb +118 -30
- data/lib/active_record/locking/optimistic.rb +32 -18
- data/lib/active_record/locking/pessimistic.rb +8 -5
- data/lib/active_record/log_subscriber.rb +39 -17
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +18 -13
- data/lib/active_record/middleware/shard_selector.rb +7 -5
- data/lib/active_record/migration/command_recorder.rb +104 -9
- data/lib/active_record/migration/compatibility.rb +158 -64
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration.rb +271 -117
- data/lib/active_record/model_schema.rb +82 -50
- data/lib/active_record/nested_attributes.rb +23 -3
- data/lib/active_record/normalization.rb +159 -0
- data/lib/active_record/persistence.rb +200 -47
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +87 -51
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +16 -3
- data/lib/active_record/railtie.rb +127 -61
- data/lib/active_record/railties/controller_runtime.rb +12 -8
- data/lib/active_record/railties/databases.rake +142 -143
- 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 +177 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +200 -83
- data/lib/active_record/relation/delegation.rb +23 -9
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +25 -1
- data/lib/active_record/relation/query_methods.rb +429 -76
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +98 -41
- data/lib/active_record/result.rb +25 -9
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +57 -16
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +65 -23
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +20 -12
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +5 -0
- data/lib/active_record/signed_id.rb +9 -7
- data/lib/active_record/store.rb +16 -11
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +138 -107
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +17 -15
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_fixtures.rb +123 -99
- data/lib/active_record/timestamp.rb +26 -14
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +39 -13
- data/lib/active_record/translation.rb +1 -1
- 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 +8 -4
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +3 -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 +50 -5
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +143 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +1 -1
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/filter.rb +1 -1
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +50 -15
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -8,8 +8,8 @@ module ActiveRecord
|
|
8
8
|
included do
|
9
9
|
##
|
10
10
|
# :singleton-method:
|
11
|
-
# Set the secret used for the signed id verifier instance when using Active Record outside of Rails.
|
12
|
-
# Within Rails, this is automatically set using the Rails application key generator.
|
11
|
+
# Set the secret used for the signed id verifier instance when using Active Record outside of \Rails.
|
12
|
+
# Within \Rails, this is automatically set using the \Rails application key generator.
|
13
13
|
class_attribute :signed_id_verifier_secret, instance_writer: false
|
14
14
|
end
|
15
15
|
|
@@ -47,7 +47,7 @@ module ActiveRecord
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
# Works like
|
50
|
+
# Works like find_signed, but will raise an +ActiveSupport::MessageVerifier::InvalidSignature+
|
51
51
|
# exception if the +signed_id+ has either expired, has a purpose mismatch, is for another record,
|
52
52
|
# or has been tampered with. It will also raise an +ActiveRecord::RecordNotFound+ exception if
|
53
53
|
# the valid signed id can't find a record.
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
end
|
67
67
|
|
68
68
|
# The verifier instance that all signed ids are generated and verified from. By default, it'll be initialized
|
69
|
-
# with the class-level +signed_id_verifier_secret+, which within Rails comes from the
|
69
|
+
# with the class-level +signed_id_verifier_secret+, which within \Rails comes from the
|
70
70
|
# Rails.application.key_generator. By default, it's SHA256 for the digest and JSON for the serialization.
|
71
71
|
def signed_id_verifier
|
72
72
|
@signed_id_verifier ||= begin
|
@@ -97,7 +97,7 @@ module ActiveRecord
|
|
97
97
|
|
98
98
|
# Returns a signed id that's generated using a preconfigured +ActiveSupport::MessageVerifier+ instance.
|
99
99
|
# This signed id is tamper proof, so it's safe to send in an email or otherwise share with the outside world.
|
100
|
-
# It can
|
100
|
+
# It can furthermore be set to expire (the default is not to expire), and scoped down with a specific purpose.
|
101
101
|
# If the expiration date has been exceeded before +find_signed+ is called, the id won't find the designated
|
102
102
|
# record. If a purpose is set, this too must match.
|
103
103
|
#
|
@@ -109,8 +109,10 @@ module ActiveRecord
|
|
109
109
|
#
|
110
110
|
# And you then change your +find_signed+ calls to require this new purpose. Any old signed ids that were not
|
111
111
|
# created with the purpose will no longer find the record.
|
112
|
-
def signed_id(expires_in: nil, purpose: nil)
|
113
|
-
|
112
|
+
def signed_id(expires_in: nil, expires_at: nil, purpose: nil)
|
113
|
+
raise ArgumentError, "Cannot get a signed_id for a new record" if new_record?
|
114
|
+
|
115
|
+
self.class.signed_id_verifier.generate id, expires_in: expires_in, expires_at: expires_at, purpose: self.class.combine_signed_id_purposes(purpose)
|
114
116
|
end
|
115
117
|
end
|
116
118
|
end
|
data/lib/active_record/store.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require "active_support/core_ext/hash/indifferent_access"
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
|
+
# = Active Record \Store
|
7
|
+
#
|
6
8
|
# Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column.
|
7
9
|
# It's like a simple key/value store baked into your record when you don't care about being able to
|
8
10
|
# query that store outside the context of a single record.
|
@@ -59,7 +61,7 @@ module ActiveRecord
|
|
59
61
|
# u.color = 'green'
|
60
62
|
# u.color_changed? # => true
|
61
63
|
# u.color_was # => 'black'
|
62
|
-
# u.color_change # => ['black', '
|
64
|
+
# u.color_change # => ['black', 'green']
|
63
65
|
#
|
64
66
|
# # Add additional accessors to an existing store through store_accessor
|
65
67
|
# class SuperUser < User
|
@@ -70,7 +72,7 @@ module ActiveRecord
|
|
70
72
|
#
|
71
73
|
# The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
|
72
74
|
#
|
73
|
-
# User.stored_attributes[:settings] # [:color, :homepage, :two_factor_auth, :login_retry]
|
75
|
+
# User.stored_attributes[:settings] # => [:color, :homepage, :two_factor_auth, :login_retry]
|
74
76
|
#
|
75
77
|
# == Overwriting default accessors
|
76
78
|
#
|
@@ -102,7 +104,8 @@ module ActiveRecord
|
|
102
104
|
|
103
105
|
module ClassMethods
|
104
106
|
def store(store_attribute, options = {})
|
105
|
-
|
107
|
+
coder = build_column_serializer(store_attribute, options[:coder], Object, options[:yaml])
|
108
|
+
serialize store_attribute, coder: IndifferentCoder.new(store_attribute, coder)
|
106
109
|
store_accessor(store_attribute, options[:accessors], **options.slice(:prefix, :suffix)) if options.has_key? :accessors
|
107
110
|
end
|
108
111
|
|
@@ -160,19 +163,19 @@ module ActiveRecord
|
|
160
163
|
|
161
164
|
define_method("saved_change_to_#{accessor_key}?") do
|
162
165
|
return false unless saved_change_to_attribute?(store_attribute)
|
163
|
-
prev_store, new_store =
|
166
|
+
prev_store, new_store = saved_changes[store_attribute]
|
164
167
|
prev_store&.dig(key) != new_store&.dig(key)
|
165
168
|
end
|
166
169
|
|
167
170
|
define_method("saved_change_to_#{accessor_key}") do
|
168
171
|
return unless saved_change_to_attribute?(store_attribute)
|
169
|
-
prev_store, new_store =
|
172
|
+
prev_store, new_store = saved_changes[store_attribute]
|
170
173
|
[prev_store&.dig(key), new_store&.dig(key)]
|
171
174
|
end
|
172
175
|
|
173
176
|
define_method("#{accessor_key}_before_last_save") do
|
174
177
|
return unless saved_change_to_attribute?(store_attribute)
|
175
|
-
prev_store, _new_store =
|
178
|
+
prev_store, _new_store = saved_changes[store_attribute]
|
176
179
|
prev_store&.dig(key)
|
177
180
|
end
|
178
181
|
end
|
@@ -225,10 +228,7 @@ module ActiveRecord
|
|
225
228
|
|
226
229
|
def self.write(object, attribute, key, value)
|
227
230
|
prepare(object, attribute)
|
228
|
-
if value != read(object, attribute, key)
|
229
|
-
object.public_send :"#{attribute}_will_change!"
|
230
|
-
object.public_send(attribute)[key] = value
|
231
|
-
end
|
231
|
+
object.public_send(attribute)[key] = value if value != read(object, attribute, key)
|
232
232
|
end
|
233
233
|
|
234
234
|
def self.prepare(object, attribute)
|
@@ -268,7 +268,7 @@ module ActiveRecord
|
|
268
268
|
end
|
269
269
|
|
270
270
|
def dump(obj)
|
271
|
-
@coder.dump
|
271
|
+
@coder.dump as_regular_hash(obj)
|
272
272
|
end
|
273
273
|
|
274
274
|
def load(yaml)
|
@@ -285,6 +285,11 @@ module ActiveRecord
|
|
285
285
|
ActiveSupport::HashWithIndifferentAccess.new
|
286
286
|
end
|
287
287
|
end
|
288
|
+
|
289
|
+
private
|
290
|
+
def as_regular_hash(obj)
|
291
|
+
obj.respond_to?(:to_hash) ? obj.to_hash : {}
|
292
|
+
end
|
288
293
|
end
|
289
294
|
end
|
290
295
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
+
# = Active Record \Suppressor
|
5
|
+
#
|
4
6
|
# ActiveRecord::Suppressor prevents the receiver from being saved during
|
5
7
|
# a given block.
|
6
8
|
#
|
@@ -32,7 +34,7 @@ module ActiveRecord
|
|
32
34
|
|
33
35
|
class << self
|
34
36
|
def registry # :nodoc:
|
35
|
-
ActiveSupport::IsolatedExecutionState[:
|
37
|
+
ActiveSupport::IsolatedExecutionState[:active_record_suppressor_registry] ||= {}
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
class TableMetadata # :nodoc:
|
5
|
-
delegate :join_primary_key, :join_foreign_key, :join_foreign_type, to: :reflection
|
5
|
+
delegate :join_primary_key, :join_primary_type, :join_foreign_key, :join_foreign_type, to: :reflection
|
6
6
|
|
7
7
|
def initialize(klass, arel_table, reflection = nil)
|
8
8
|
@klass = klass
|
@@ -19,11 +19,20 @@ module ActiveRecord
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def has_column?(column_name)
|
22
|
-
klass&.columns_hash
|
22
|
+
klass&.columns_hash&.key?(column_name)
|
23
23
|
end
|
24
24
|
|
25
25
|
def associated_with?(table_name)
|
26
|
-
|
26
|
+
if reflection = klass&._reflect_on_association(table_name)
|
27
|
+
reflection
|
28
|
+
elsif ActiveRecord.allow_deprecated_singular_associations_name && reflection = klass&._reflect_on_association(table_name.singularize)
|
29
|
+
ActiveRecord.deprecator.warn(<<~MSG)
|
30
|
+
Referring to a singular association (e.g. `#{reflection.name}`) by its plural name (e.g. `#{reflection.plural_name}`) is deprecated.
|
31
|
+
|
32
|
+
To convert this deprecation warning to an error and enable more performant behavior, set config.active_record.allow_deprecated_singular_associations_name = false.
|
33
|
+
MSG
|
34
|
+
reflection
|
35
|
+
end
|
27
36
|
end
|
28
37
|
|
29
38
|
def associated_table(table_name)
|
@@ -54,6 +63,10 @@ module ActiveRecord
|
|
54
63
|
reflection&.polymorphic?
|
55
64
|
end
|
56
65
|
|
66
|
+
def polymorphic_name_association
|
67
|
+
reflection&.polymorphic_name
|
68
|
+
end
|
69
|
+
|
57
70
|
def through_association?
|
58
71
|
reflection&.through_reflection?
|
59
72
|
end
|
@@ -6,14 +6,16 @@ module ActiveRecord
|
|
6
6
|
module Tasks # :nodoc:
|
7
7
|
class DatabaseNotSupported < StandardError; end # :nodoc:
|
8
8
|
|
9
|
+
# = Active Record \DatabaseTasks
|
10
|
+
#
|
9
11
|
# ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
|
10
12
|
# logic behind common tasks used to manage database and migrations.
|
11
13
|
#
|
12
|
-
# The tasks defined here are used with Rails commands provided by Active Record.
|
14
|
+
# The tasks defined here are used with \Rails commands provided by Active Record.
|
13
15
|
#
|
14
16
|
# In order to use DatabaseTasks, a few config values need to be set. All the needed
|
15
|
-
# config values are set by Rails already, so it's necessary to do it only if you
|
16
|
-
# want to change the defaults or when you want to use Active Record outside of Rails
|
17
|
+
# config values are set by \Rails already, so it's necessary to do it only if you
|
18
|
+
# want to change the defaults or when you want to use Active Record outside of \Rails
|
17
19
|
# (in such case after configuring the database tasks, you can also use the rake tasks
|
18
20
|
# defined in Active Record).
|
19
21
|
#
|
@@ -27,7 +29,7 @@ module ActiveRecord
|
|
27
29
|
# * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
|
28
30
|
# * +root+: a path to the root of the application.
|
29
31
|
#
|
30
|
-
# Example usage of DatabaseTasks outside Rails could look as such:
|
32
|
+
# Example usage of DatabaseTasks outside \Rails could look as such:
|
31
33
|
#
|
32
34
|
# include ActiveRecord::Tasks
|
33
35
|
# DatabaseTasks.database_configuration = YAML.load_file('my_database_config.yml')
|
@@ -60,20 +62,12 @@ module ActiveRecord
|
|
60
62
|
|
61
63
|
LOCAL_HOSTS = ["127.0.0.1", "localhost"]
|
62
64
|
|
63
|
-
def check_protected_environments!
|
64
|
-
|
65
|
-
current = ActiveRecord::Base.connection.migration_context.current_environment
|
66
|
-
stored = ActiveRecord::Base.connection.migration_context.last_stored_environment
|
67
|
-
|
68
|
-
if ActiveRecord::Base.connection.migration_context.protected_environment?
|
69
|
-
raise ActiveRecord::ProtectedEnvironmentError.new(stored)
|
70
|
-
end
|
65
|
+
def check_protected_environments!(environment = env)
|
66
|
+
return if ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]
|
71
67
|
|
72
|
-
|
73
|
-
|
74
|
-
end
|
68
|
+
configs_for(env_name: environment).each do |db_config|
|
69
|
+
check_current_protected_environment!(db_config)
|
75
70
|
end
|
76
|
-
rescue ActiveRecord::NoDatabaseError
|
77
71
|
end
|
78
72
|
|
79
73
|
def register_task(pattern, task)
|
@@ -82,6 +76,7 @@ module ActiveRecord
|
|
82
76
|
end
|
83
77
|
|
84
78
|
register_task(/mysql/, "ActiveRecord::Tasks::MySQLDatabaseTasks")
|
79
|
+
register_task(/trilogy/, "ActiveRecord::Tasks::MySQLDatabaseTasks")
|
85
80
|
register_task(/postgresql/, "ActiveRecord::Tasks::PostgreSQLDatabaseTasks")
|
86
81
|
register_task(/sqlite/, "ActiveRecord::Tasks::SQLiteDatabaseTasks")
|
87
82
|
|
@@ -130,28 +125,20 @@ module ActiveRecord
|
|
130
125
|
end
|
131
126
|
|
132
127
|
def create_all
|
133
|
-
|
128
|
+
db_config = migration_connection.pool.db_config
|
129
|
+
|
134
130
|
each_local_configuration { |db_config| create(db_config) }
|
135
|
-
|
136
|
-
|
137
|
-
end
|
131
|
+
|
132
|
+
migration_class.establish_connection(db_config)
|
138
133
|
end
|
139
134
|
|
140
|
-
def setup_initial_database_yaml
|
135
|
+
def setup_initial_database_yaml # :nodoc:
|
141
136
|
return {} unless defined?(Rails)
|
142
137
|
|
143
|
-
|
144
|
-
Rails.application.config.load_database_yaml
|
145
|
-
rescue
|
146
|
-
unless ActiveRecord.suppress_multiple_database_warning
|
147
|
-
$stderr.puts "Rails couldn't infer whether you are using multiple databases from your database.yml and can't generate the tasks for the non-primary databases. If you'd like to use this feature, please simplify your ERB."
|
148
|
-
end
|
149
|
-
|
150
|
-
{}
|
151
|
-
end
|
138
|
+
Rails.application.config.load_database_yaml
|
152
139
|
end
|
153
140
|
|
154
|
-
def for_each(databases)
|
141
|
+
def for_each(databases) # :nodoc:
|
155
142
|
return {} unless defined?(Rails)
|
156
143
|
|
157
144
|
database_configs = ActiveRecord::DatabaseConfigurations.new(databases).configs_for(env_name: Rails.env)
|
@@ -166,7 +153,7 @@ module ActiveRecord
|
|
166
153
|
end
|
167
154
|
end
|
168
155
|
|
169
|
-
def raise_for_multi_db(environment = env, command:)
|
156
|
+
def raise_for_multi_db(environment = env, command:) # :nodoc:
|
170
157
|
db_configs = configs_for(env_name: environment)
|
171
158
|
|
172
159
|
if db_configs.count > 1
|
@@ -182,38 +169,35 @@ module ActiveRecord
|
|
182
169
|
|
183
170
|
def create_current(environment = env, name = nil)
|
184
171
|
each_current_configuration(environment, name) { |db_config| create(db_config) }
|
185
|
-
|
172
|
+
|
173
|
+
migration_class.establish_connection(environment.to_sym)
|
186
174
|
end
|
187
175
|
|
188
176
|
def prepare_all
|
189
177
|
seed = false
|
190
178
|
|
191
|
-
|
192
|
-
|
179
|
+
each_current_configuration(env) do |db_config|
|
180
|
+
with_temporary_pool(db_config) do
|
181
|
+
begin
|
182
|
+
database_initialized = migration_connection.schema_migration.table_exists?
|
183
|
+
rescue ActiveRecord::NoDatabaseError
|
184
|
+
create(db_config)
|
185
|
+
retry
|
186
|
+
end
|
193
187
|
|
194
|
-
|
195
|
-
|
188
|
+
unless database_initialized
|
189
|
+
if File.exist?(schema_dump_path(db_config))
|
190
|
+
load_schema(db_config, ActiveRecord.schema_format, nil)
|
191
|
+
end
|
192
|
+
|
193
|
+
seed = true
|
194
|
+
end
|
196
195
|
|
197
|
-
if ActiveRecord.dump_schema_after_migration
|
198
|
-
dump_schema(db_config, ActiveRecord.schema_format)
|
199
|
-
end
|
200
|
-
rescue ActiveRecord::NoDatabaseError
|
201
|
-
create_current(db_config.env_name, db_config.name)
|
202
|
-
|
203
|
-
if File.exist?(schema_dump_path(db_config))
|
204
|
-
load_schema(
|
205
|
-
db_config,
|
206
|
-
ActiveRecord.schema_format,
|
207
|
-
nil
|
208
|
-
)
|
209
|
-
else
|
210
196
|
migrate
|
197
|
+
dump_schema(db_config) if ActiveRecord.dump_schema_after_migration
|
211
198
|
end
|
212
|
-
|
213
|
-
seed = true
|
214
199
|
end
|
215
200
|
|
216
|
-
ActiveRecord::Base.establish_connection
|
217
201
|
load_seed if seed
|
218
202
|
end
|
219
203
|
|
@@ -238,10 +222,9 @@ module ActiveRecord
|
|
238
222
|
end
|
239
223
|
|
240
224
|
def truncate_tables(db_config)
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
connection.truncate_tables(*connection.tables)
|
225
|
+
with_temporary_connection(db_config) do |conn|
|
226
|
+
conn.truncate_tables(*conn.tables)
|
227
|
+
end
|
245
228
|
end
|
246
229
|
private :truncate_tables
|
247
230
|
|
@@ -252,18 +235,22 @@ module ActiveRecord
|
|
252
235
|
end
|
253
236
|
|
254
237
|
def migrate(version = nil)
|
255
|
-
check_target_version
|
256
|
-
|
257
238
|
scope = ENV["SCOPE"]
|
258
239
|
verbose_was, Migration.verbose = Migration.verbose, verbose?
|
259
240
|
|
260
|
-
|
261
|
-
|
241
|
+
check_target_version
|
242
|
+
|
243
|
+
migration_connection.migration_context.migrate(target_version) do |migration|
|
244
|
+
if version.blank?
|
245
|
+
scope.blank? || scope == migration.scope
|
246
|
+
else
|
247
|
+
migration.version == version
|
248
|
+
end
|
262
249
|
end.tap do |migrations_ran|
|
263
250
|
Migration.write("No migrations ran. (using #{scope} scope)") if scope.present? && migrations_ran.empty?
|
264
251
|
end
|
265
252
|
|
266
|
-
|
253
|
+
migration_connection.schema_cache.clear!
|
267
254
|
ensure
|
268
255
|
Migration.verbose = verbose_was
|
269
256
|
end
|
@@ -271,9 +258,9 @@ module ActiveRecord
|
|
271
258
|
def db_configs_with_versions(db_configs) # :nodoc:
|
272
259
|
db_configs_with_versions = Hash.new { |h, k| h[k] = [] }
|
273
260
|
|
274
|
-
|
275
|
-
|
276
|
-
versions_to_run =
|
261
|
+
with_temporary_connection_for_each do |conn|
|
262
|
+
db_config = conn.pool.db_config
|
263
|
+
versions_to_run = conn.migration_context.pending_migration_versions
|
277
264
|
target_version = ActiveRecord::Tasks::DatabaseTasks.target_version
|
278
265
|
|
279
266
|
versions_to_run.each do |version|
|
@@ -286,22 +273,22 @@ module ActiveRecord
|
|
286
273
|
end
|
287
274
|
|
288
275
|
def migrate_status
|
289
|
-
unless
|
276
|
+
unless migration_connection.schema_migration.table_exists?
|
290
277
|
Kernel.abort "Schema migrations table does not exist yet."
|
291
278
|
end
|
292
279
|
|
293
280
|
# output
|
294
|
-
puts "\ndatabase: #{
|
281
|
+
puts "\ndatabase: #{migration_connection.pool.db_config.database}\n\n"
|
295
282
|
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
296
283
|
puts "-" * 50
|
297
|
-
|
284
|
+
migration_connection.migration_context.migrations_status.each do |status, version, name|
|
298
285
|
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
|
299
286
|
end
|
300
287
|
puts
|
301
288
|
end
|
302
289
|
|
303
290
|
def check_target_version
|
304
|
-
if target_version && !
|
291
|
+
if target_version && !Migration.valid_version_format?(ENV["VERSION"])
|
305
292
|
raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`"
|
306
293
|
end
|
307
294
|
end
|
@@ -341,7 +328,8 @@ module ActiveRecord
|
|
341
328
|
|
342
329
|
def purge_current(environment = env)
|
343
330
|
each_current_configuration(environment) { |db_config| purge(db_config) }
|
344
|
-
|
331
|
+
|
332
|
+
migration_class.establish_connection(environment.to_sym)
|
345
333
|
end
|
346
334
|
|
347
335
|
def structure_dump(configuration, *arguments)
|
@@ -360,10 +348,10 @@ module ActiveRecord
|
|
360
348
|
|
361
349
|
def load_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
|
362
350
|
file ||= schema_dump_path(db_config, format)
|
351
|
+
return unless file
|
363
352
|
|
364
353
|
verbose_was, Migration.verbose = Migration.verbose, verbose? && ENV["VERBOSE"]
|
365
354
|
check_schema_file(file)
|
366
|
-
ActiveRecord::Base.establish_connection(db_config)
|
367
355
|
|
368
356
|
case format
|
369
357
|
when :ruby
|
@@ -373,9 +361,8 @@ module ActiveRecord
|
|
373
361
|
else
|
374
362
|
raise ArgumentError, "unknown format #{format.inspect}"
|
375
363
|
end
|
376
|
-
|
377
|
-
|
378
|
-
ActiveRecord::InternalMetadata[:schema_sha1] = schema_sha1(file)
|
364
|
+
|
365
|
+
migration_connection.internal_metadata.create_table_and_set_flags(db_config.env_name, schema_sha1(file))
|
379
366
|
ensure
|
380
367
|
Migration.verbose = verbose_was
|
381
368
|
end
|
@@ -385,66 +372,58 @@ module ActiveRecord
|
|
385
372
|
|
386
373
|
file ||= schema_dump_path(db_config)
|
387
374
|
|
388
|
-
return true unless File.exist?(file)
|
375
|
+
return true unless file && File.exist?(file)
|
389
376
|
|
390
|
-
|
377
|
+
with_temporary_connection(db_config) do |connection|
|
378
|
+
return false unless connection.internal_metadata.enabled?
|
379
|
+
return false unless connection.internal_metadata.table_exists?
|
391
380
|
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
ActiveRecord::InternalMetadata[:schema_sha1] == schema_sha1(file)
|
381
|
+
connection.internal_metadata[:schema_sha1] == schema_sha1(file)
|
382
|
+
end
|
396
383
|
end
|
397
384
|
|
398
385
|
def reconstruct_from_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
|
399
386
|
file ||= schema_dump_path(db_config, format)
|
400
387
|
|
401
|
-
check_schema_file(file)
|
402
|
-
|
403
|
-
ActiveRecord::Base.establish_connection(db_config)
|
388
|
+
check_schema_file(file) if file
|
404
389
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
390
|
+
with_temporary_pool(db_config, clobber: true) do
|
391
|
+
if schema_up_to_date?(db_config, format, file)
|
392
|
+
truncate_tables(db_config)
|
393
|
+
else
|
394
|
+
purge(db_config)
|
395
|
+
load_schema(db_config, format, file)
|
396
|
+
end
|
397
|
+
rescue ActiveRecord::NoDatabaseError
|
398
|
+
create(db_config)
|
409
399
|
load_schema(db_config, format, file)
|
410
400
|
end
|
411
|
-
rescue ActiveRecord::NoDatabaseError
|
412
|
-
create(db_config)
|
413
|
-
load_schema(db_config, format, file)
|
414
401
|
end
|
415
402
|
|
416
403
|
def dump_schema(db_config, format = ActiveRecord.schema_format) # :nodoc:
|
404
|
+
return unless db_config.schema_dump
|
405
|
+
|
417
406
|
require "active_record/schema_dumper"
|
418
407
|
filename = schema_dump_path(db_config, format)
|
419
|
-
|
408
|
+
return unless filename
|
420
409
|
|
421
410
|
FileUtils.mkdir_p(db_dir)
|
422
411
|
case format
|
423
412
|
when :ruby
|
424
413
|
File.open(filename, "w:utf-8") do |file|
|
425
|
-
ActiveRecord::SchemaDumper.dump(
|
414
|
+
ActiveRecord::SchemaDumper.dump(migration_connection, file)
|
426
415
|
end
|
427
416
|
when :sql
|
428
417
|
structure_dump(db_config, filename)
|
429
|
-
if
|
418
|
+
if migration_connection.schema_migration.table_exists?
|
430
419
|
File.open(filename, "a") do |f|
|
431
|
-
f.puts
|
420
|
+
f.puts migration_connection.dump_schema_information
|
432
421
|
f.print "\n"
|
433
422
|
end
|
434
423
|
end
|
435
424
|
end
|
436
425
|
end
|
437
426
|
|
438
|
-
def schema_file_type(format = ActiveRecord.schema_format)
|
439
|
-
case format
|
440
|
-
when :ruby
|
441
|
-
"schema.rb"
|
442
|
-
when :sql
|
443
|
-
"structure.sql"
|
444
|
-
end
|
445
|
-
end
|
446
|
-
deprecate :schema_file_type
|
447
|
-
|
448
427
|
def schema_dump_path(db_config, format = ActiveRecord.schema_format)
|
449
428
|
return ENV["SCHEMA"] if ENV["SCHEMA"]
|
450
429
|
|
@@ -470,9 +449,10 @@ module ActiveRecord
|
|
470
449
|
|
471
450
|
def load_schema_current(format = ActiveRecord.schema_format, file = nil, environment = env)
|
472
451
|
each_current_configuration(environment) do |db_config|
|
473
|
-
|
452
|
+
with_temporary_connection(db_config) do
|
453
|
+
load_schema(db_config, format, file)
|
454
|
+
end
|
474
455
|
end
|
475
|
-
ActiveRecord::Base.establish_connection(environment.to_sym)
|
476
456
|
end
|
477
457
|
|
478
458
|
def check_schema_file(filename)
|
@@ -495,7 +475,7 @@ module ActiveRecord
|
|
495
475
|
|
496
476
|
# Dumps the schema cache in YAML format for the connection into the file
|
497
477
|
#
|
498
|
-
# ==== Examples
|
478
|
+
# ==== Examples
|
499
479
|
# ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.connection, "tmp/schema_dump.yaml")
|
500
480
|
def dump_schema_cache(conn, filename)
|
501
481
|
conn.schema_cache.dump_to(filename)
|
@@ -505,7 +485,41 @@ module ActiveRecord
|
|
505
485
|
FileUtils.rm_f filename, verbose: false
|
506
486
|
end
|
507
487
|
|
488
|
+
def with_temporary_connection_for_each(env: ActiveRecord::Tasks::DatabaseTasks.env, name: nil, clobber: false, &block) # :nodoc:
|
489
|
+
if name
|
490
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: env, name: name)
|
491
|
+
with_temporary_connection(db_config, clobber: clobber, &block)
|
492
|
+
else
|
493
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env, name: name).each do |db_config|
|
494
|
+
with_temporary_connection(db_config, clobber: clobber, &block)
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
def with_temporary_connection(db_config, clobber: false) # :nodoc:
|
500
|
+
with_temporary_pool(db_config, clobber: clobber) do |pool|
|
501
|
+
yield pool.connection
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
def migration_class # :nodoc:
|
506
|
+
ActiveRecord::Base
|
507
|
+
end
|
508
|
+
|
509
|
+
def migration_connection # :nodoc:
|
510
|
+
migration_class.connection
|
511
|
+
end
|
512
|
+
|
508
513
|
private
|
514
|
+
def with_temporary_pool(db_config, clobber: false)
|
515
|
+
original_db_config = migration_class.connection_db_config
|
516
|
+
pool = migration_class.connection_handler.establish_connection(db_config, clobber: clobber)
|
517
|
+
|
518
|
+
yield pool
|
519
|
+
ensure
|
520
|
+
migration_class.connection_handler.establish_connection(original_db_config, clobber: clobber)
|
521
|
+
end
|
522
|
+
|
509
523
|
def configs_for(**options)
|
510
524
|
Base.configurations.configs_for(**options)
|
511
525
|
end
|
@@ -586,6 +600,23 @@ module ActiveRecord
|
|
586
600
|
structure_load_flags
|
587
601
|
end
|
588
602
|
end
|
603
|
+
|
604
|
+
def check_current_protected_environment!(db_config)
|
605
|
+
with_temporary_pool(db_config) do |pool|
|
606
|
+
connection = pool.connection
|
607
|
+
current = connection.migration_context.current_environment
|
608
|
+
stored = connection.migration_context.last_stored_environment
|
609
|
+
|
610
|
+
if connection.migration_context.protected_environment?
|
611
|
+
raise ActiveRecord::ProtectedEnvironmentError.new(stored)
|
612
|
+
end
|
613
|
+
|
614
|
+
if stored && stored != current
|
615
|
+
raise ActiveRecord::EnvironmentMismatchError.new(current: current, stored: stored)
|
616
|
+
end
|
617
|
+
rescue ActiveRecord::NoDatabaseError
|
618
|
+
end
|
619
|
+
end
|
589
620
|
end
|
590
621
|
end
|
591
622
|
end
|