activerecord 6.1.7 → 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 +1516 -1019
- data/MIT-LICENSE +1 -1
- data/README.rdoc +17 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +50 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- 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 +6 -2
- data/lib/active_record/associations/collection_association.rb +35 -31
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +26 -16
- data/lib/active_record/associations/preloader/association.rb +207 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +423 -289
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +61 -14
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +25 -10
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +10 -13
- data/lib/active_record/attribute_methods.rb +121 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +61 -30
- data/lib/active_record/base.rb +25 -2
- data/lib/active_record/callbacks.rb +18 -34
- 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 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -51
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +360 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +622 -149
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- 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 +104 -53
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +18 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- 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 +12 -3
- 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 +30 -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 +89 -56
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +381 -69
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +492 -230
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +65 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
- 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 +9 -6
- data/lib/active_record/connection_handling.rb +107 -136
- data/lib/active_record/core.rb +194 -224
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +84 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +61 -15
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -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/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +224 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -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 +172 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -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 +92 -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 +96 -0
- data/lib/active_record/encryption.rb +56 -0
- data/lib/active_record/enum.rb +156 -62
- data/lib/active_record/errors.rb +171 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -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 +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +131 -86
- data/lib/active_record/future_result.rb +164 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +133 -20
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +117 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +36 -21
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- 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 +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +108 -13
- data/lib/active_record/migration/compatibility.rb +221 -48
- 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/join_table.rb +1 -1
- data/lib/active_record/migration.rb +355 -171
- data/lib/active_record/model_schema.rb +116 -97
- data/lib/active_record/nested_attributes.rb +36 -15
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +159 -0
- data/lib/active_record/persistence.rb +405 -85
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +219 -43
- data/lib/active_record/railties/controller_runtime.rb +13 -9
- data/lib/active_record/railties/databases.rake +185 -249
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +229 -80
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +211 -90
- data/lib/active_record/relation/delegation.rb +27 -13
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- 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 +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +654 -127
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +262 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +18 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +225 -136
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +116 -96
- data/lib/active_record/timestamp.rb +28 -17
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- 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 +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- 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/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +139 -19
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- 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
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +92 -13
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -9,7 +9,7 @@ require "active_support/core_ext/module/attribute_accessors"
|
|
9
9
|
require "active_support/actionable_error"
|
10
10
|
|
11
11
|
module ActiveRecord
|
12
|
-
class MigrationError < ActiveRecordError
|
12
|
+
class MigrationError < ActiveRecordError # :nodoc:
|
13
13
|
def initialize(message = nil)
|
14
14
|
message = "\n\n#{message}\n\n" if message
|
15
15
|
super
|
@@ -20,7 +20,7 @@ module ActiveRecord
|
|
20
20
|
# For example the following migration is not reversible.
|
21
21
|
# Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
|
22
22
|
#
|
23
|
-
# class IrreversibleMigrationExample < ActiveRecord::Migration[
|
23
|
+
# class IrreversibleMigrationExample < ActiveRecord::Migration[7.1]
|
24
24
|
# def change
|
25
25
|
# create_table :distributors do |t|
|
26
26
|
# t.string :zipcode
|
@@ -38,7 +38,7 @@ module ActiveRecord
|
|
38
38
|
#
|
39
39
|
# 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
|
40
40
|
#
|
41
|
-
# class ReversibleMigrationExample < ActiveRecord::Migration[
|
41
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[7.1]
|
42
42
|
# def up
|
43
43
|
# create_table :distributors do |t|
|
44
44
|
# t.string :zipcode
|
@@ -63,7 +63,7 @@ module ActiveRecord
|
|
63
63
|
#
|
64
64
|
# 2. Use the #reversible method in <tt>#change</tt> method:
|
65
65
|
#
|
66
|
-
# class ReversibleMigrationExample < ActiveRecord::Migration[
|
66
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[7.1]
|
67
67
|
# def change
|
68
68
|
# create_table :distributors do |t|
|
69
69
|
# t.string :zipcode
|
@@ -90,7 +90,7 @@ module ActiveRecord
|
|
90
90
|
class IrreversibleMigration < MigrationError
|
91
91
|
end
|
92
92
|
|
93
|
-
class DuplicateMigrationVersionError < MigrationError
|
93
|
+
class DuplicateMigrationVersionError < MigrationError # :nodoc:
|
94
94
|
def initialize(version = nil)
|
95
95
|
if version
|
96
96
|
super("Multiple migrations have the version number #{version}.")
|
@@ -100,7 +100,7 @@ module ActiveRecord
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
class DuplicateMigrationNameError < MigrationError
|
103
|
+
class DuplicateMigrationNameError < MigrationError # :nodoc:
|
104
104
|
def initialize(name = nil)
|
105
105
|
if name
|
106
106
|
super("Multiple migrations have the name #{name}.")
|
@@ -110,7 +110,7 @@ module ActiveRecord
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
-
class UnknownMigrationVersionError < MigrationError
|
113
|
+
class UnknownMigrationVersionError < MigrationError # :nodoc:
|
114
114
|
def initialize(version = nil)
|
115
115
|
if version
|
116
116
|
super("No migration with version number #{version}.")
|
@@ -120,7 +120,7 @@ module ActiveRecord
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
-
class IllegalMigrationNameError < MigrationError
|
123
|
+
class IllegalMigrationNameError < MigrationError # :nodoc:
|
124
124
|
def initialize(name = nil)
|
125
125
|
if name
|
126
126
|
super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
|
@@ -130,42 +130,48 @@ module ActiveRecord
|
|
130
130
|
end
|
131
131
|
end
|
132
132
|
|
133
|
-
class PendingMigrationError < MigrationError
|
133
|
+
class PendingMigrationError < MigrationError # :nodoc:
|
134
134
|
include ActiveSupport::ActionableError
|
135
135
|
|
136
136
|
action "Run pending migrations" do
|
137
137
|
ActiveRecord::Tasks::DatabaseTasks.migrate
|
138
138
|
|
139
|
-
if ActiveRecord
|
140
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
141
|
-
|
142
|
-
)
|
139
|
+
if ActiveRecord.dump_schema_after_migration
|
140
|
+
connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
141
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(connection.pool.db_config)
|
143
142
|
end
|
144
143
|
end
|
145
144
|
|
146
|
-
def initialize(message = nil)
|
147
|
-
|
145
|
+
def initialize(message = nil, pending_migrations: nil)
|
146
|
+
if pending_migrations.nil?
|
147
|
+
connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
148
|
+
pending_migrations = connection.migration_context.open.pending_migrations
|
149
|
+
end
|
150
|
+
|
151
|
+
super(message || detailed_migration_message(pending_migrations))
|
148
152
|
end
|
149
153
|
|
150
154
|
private
|
151
|
-
def detailed_migration_message
|
155
|
+
def detailed_migration_message(pending_migrations)
|
152
156
|
message = "Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate"
|
153
|
-
message += " RAILS_ENV=#{::Rails.env}" if defined?(Rails.env)
|
157
|
+
message += " RAILS_ENV=#{::Rails.env}" if defined?(Rails.env) && !Rails.env.local?
|
154
158
|
message += "\n\n"
|
155
159
|
|
156
|
-
pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
|
157
|
-
|
158
160
|
message += "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}\n\n"
|
159
161
|
|
160
162
|
pending_migrations.each do |pending_migration|
|
161
|
-
message += "#{pending_migration.
|
163
|
+
message += "#{pending_migration.filename}\n"
|
162
164
|
end
|
163
165
|
|
164
166
|
message
|
165
167
|
end
|
168
|
+
|
169
|
+
def connection
|
170
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
171
|
+
end
|
166
172
|
end
|
167
173
|
|
168
|
-
class ConcurrentMigrationError < MigrationError
|
174
|
+
class ConcurrentMigrationError < MigrationError # :nodoc:
|
169
175
|
DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
|
170
176
|
RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock"
|
171
177
|
|
@@ -174,7 +180,7 @@ module ActiveRecord
|
|
174
180
|
end
|
175
181
|
end
|
176
182
|
|
177
|
-
class NoEnvironmentInSchemaError < MigrationError
|
183
|
+
class NoEnvironmentInSchemaError < MigrationError # :nodoc:
|
178
184
|
def initialize
|
179
185
|
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
|
180
186
|
if defined?(Rails.env)
|
@@ -185,7 +191,7 @@ module ActiveRecord
|
|
185
191
|
end
|
186
192
|
end
|
187
193
|
|
188
|
-
class ProtectedEnvironmentError < ActiveRecordError
|
194
|
+
class ProtectedEnvironmentError < ActiveRecordError # :nodoc:
|
189
195
|
def initialize(env = "production")
|
190
196
|
msg = +"You are attempting to run a destructive action against your '#{env}' database.\n"
|
191
197
|
msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
|
@@ -228,7 +234,7 @@ module ActiveRecord
|
|
228
234
|
#
|
229
235
|
# Example of a simple migration:
|
230
236
|
#
|
231
|
-
# class AddSsl < ActiveRecord::Migration[
|
237
|
+
# class AddSsl < ActiveRecord::Migration[7.1]
|
232
238
|
# def up
|
233
239
|
# add_column :accounts, :ssl_enabled, :boolean, default: true
|
234
240
|
# end
|
@@ -248,7 +254,7 @@ module ActiveRecord
|
|
248
254
|
#
|
249
255
|
# Example of a more complex migration that also needs to initialize data:
|
250
256
|
#
|
251
|
-
# class AddSystemSettings < ActiveRecord::Migration[
|
257
|
+
# class AddSystemSettings < ActiveRecord::Migration[7.1]
|
252
258
|
# def up
|
253
259
|
# create_table :system_settings do |t|
|
254
260
|
# t.string :name
|
@@ -326,7 +332,7 @@ module ActiveRecord
|
|
326
332
|
# details.
|
327
333
|
# * <tt>change_table(name, options)</tt>: Allows to make column alterations to
|
328
334
|
# the table called +name+. It makes the table object available to a block that
|
329
|
-
# can then add/remove columns, indexes or foreign keys to it.
|
335
|
+
# can then add/remove columns, indexes, or foreign keys to it.
|
330
336
|
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
|
331
337
|
# a column but keeps the type and content.
|
332
338
|
# * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
|
@@ -356,12 +362,12 @@ module ActiveRecord
|
|
356
362
|
# == Irreversible transformations
|
357
363
|
#
|
358
364
|
# Some transformations are destructive in a manner that cannot be reversed.
|
359
|
-
# Migrations of that kind should raise an
|
365
|
+
# Migrations of that kind should raise an ActiveRecord::IrreversibleMigration
|
360
366
|
# exception in their +down+ method.
|
361
367
|
#
|
362
|
-
# == Running migrations from within Rails
|
368
|
+
# == Running migrations from within \Rails
|
363
369
|
#
|
364
|
-
# The Rails package has several tools to help create and apply migrations.
|
370
|
+
# The \Rails package has several tools to help create and apply migrations.
|
365
371
|
#
|
366
372
|
# To generate a new migration, you can use
|
367
373
|
# bin/rails generate migration MyNewMigration
|
@@ -376,7 +382,7 @@ module ActiveRecord
|
|
376
382
|
# bin/rails generate migration add_fieldname_to_tablename fieldname:string
|
377
383
|
#
|
378
384
|
# This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
|
379
|
-
# class AddFieldnameToTablename < ActiveRecord::Migration[
|
385
|
+
# class AddFieldnameToTablename < ActiveRecord::Migration[7.1]
|
380
386
|
# def change
|
381
387
|
# add_column :tablenames, :fieldname, :string
|
382
388
|
# end
|
@@ -395,14 +401,14 @@ module ActiveRecord
|
|
395
401
|
# wish to rollback last few migrations. <tt>bin/rails db:rollback STEP=2</tt> will rollback
|
396
402
|
# the latest two migrations.
|
397
403
|
#
|
398
|
-
# If any of the migrations throw an
|
404
|
+
# If any of the migrations throw an ActiveRecord::IrreversibleMigration exception,
|
399
405
|
# that step will fail and you'll have some manual work to do.
|
400
406
|
#
|
401
407
|
# == More examples
|
402
408
|
#
|
403
409
|
# Not all migrations change the schema. Some just fix the data:
|
404
410
|
#
|
405
|
-
# class RemoveEmptyTags < ActiveRecord::Migration[
|
411
|
+
# class RemoveEmptyTags < ActiveRecord::Migration[7.1]
|
406
412
|
# def up
|
407
413
|
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
|
408
414
|
# end
|
@@ -415,7 +421,7 @@ module ActiveRecord
|
|
415
421
|
#
|
416
422
|
# Others remove columns when they migrate up instead of down:
|
417
423
|
#
|
418
|
-
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[
|
424
|
+
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.1]
|
419
425
|
# def up
|
420
426
|
# remove_column :items, :incomplete_items_count
|
421
427
|
# remove_column :items, :completed_items_count
|
@@ -429,7 +435,7 @@ module ActiveRecord
|
|
429
435
|
#
|
430
436
|
# And sometimes you need to do something in SQL not abstracted directly by migrations:
|
431
437
|
#
|
432
|
-
# class MakeJoinUnique < ActiveRecord::Migration[
|
438
|
+
# class MakeJoinUnique < ActiveRecord::Migration[7.1]
|
433
439
|
# def up
|
434
440
|
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
|
435
441
|
# end
|
@@ -446,7 +452,7 @@ module ActiveRecord
|
|
446
452
|
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
|
447
453
|
# latest column data from after the new column was added. Example:
|
448
454
|
#
|
449
|
-
# class AddPeopleSalary < ActiveRecord::Migration[
|
455
|
+
# class AddPeopleSalary < ActiveRecord::Migration[7.1]
|
450
456
|
# def up
|
451
457
|
# add_column :people, :salary, :integer
|
452
458
|
# Person.reset_column_information
|
@@ -482,7 +488,7 @@ module ActiveRecord
|
|
482
488
|
#
|
483
489
|
# == Timestamped Migrations
|
484
490
|
#
|
485
|
-
# By default, Rails generates migrations that look like:
|
491
|
+
# By default, \Rails generates migrations that look like:
|
486
492
|
#
|
487
493
|
# 20080717013526_your_migration_name.rb
|
488
494
|
#
|
@@ -504,7 +510,7 @@ module ActiveRecord
|
|
504
510
|
# To define a reversible migration, define the +change+ method in your
|
505
511
|
# migration like this:
|
506
512
|
#
|
507
|
-
# class TenderloveMigration < ActiveRecord::Migration[
|
513
|
+
# class TenderloveMigration < ActiveRecord::Migration[7.1]
|
508
514
|
# def change
|
509
515
|
# create_table(:horses) do |t|
|
510
516
|
# t.column :content, :text
|
@@ -521,11 +527,11 @@ module ActiveRecord
|
|
521
527
|
# as before.
|
522
528
|
#
|
523
529
|
# If a command cannot be reversed, an
|
524
|
-
#
|
530
|
+
# ActiveRecord::IrreversibleMigration exception will be raised when
|
525
531
|
# the migration is moving down.
|
526
532
|
#
|
527
533
|
# For a list of commands that are reversible, please see
|
528
|
-
#
|
534
|
+
# +ActiveRecord::Migration::CommandRecorder+.
|
529
535
|
#
|
530
536
|
# == Transactional Migrations
|
531
537
|
#
|
@@ -534,7 +540,7 @@ module ActiveRecord
|
|
534
540
|
# can't execute inside a transaction though, and for these situations
|
535
541
|
# you can turn the automatic transactions off.
|
536
542
|
#
|
537
|
-
# class ChangeEnum < ActiveRecord::Migration[
|
543
|
+
# class ChangeEnum < ActiveRecord::Migration[7.1]
|
538
544
|
# disable_ddl_transaction!
|
539
545
|
#
|
540
546
|
# def up
|
@@ -548,18 +554,57 @@ module ActiveRecord
|
|
548
554
|
autoload :CommandRecorder, "active_record/migration/command_recorder"
|
549
555
|
autoload :Compatibility, "active_record/migration/compatibility"
|
550
556
|
autoload :JoinTable, "active_record/migration/join_table"
|
557
|
+
autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
|
558
|
+
autoload :DefaultStrategy, "active_record/migration/default_strategy"
|
551
559
|
|
552
560
|
# This must be defined before the inherited hook, below
|
553
|
-
class Current < Migration
|
561
|
+
class Current < Migration # :nodoc:
|
562
|
+
def create_table(table_name, **options)
|
563
|
+
if block_given?
|
564
|
+
super { |t| yield compatible_table_definition(t) }
|
565
|
+
else
|
566
|
+
super
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
def change_table(table_name, **options)
|
571
|
+
if block_given?
|
572
|
+
super { |t| yield compatible_table_definition(t) }
|
573
|
+
else
|
574
|
+
super
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
def create_join_table(table_1, table_2, **options)
|
579
|
+
if block_given?
|
580
|
+
super { |t| yield compatible_table_definition(t) }
|
581
|
+
else
|
582
|
+
super
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
def drop_table(table_name, **options)
|
587
|
+
if block_given?
|
588
|
+
super { |t| yield compatible_table_definition(t) }
|
589
|
+
else
|
590
|
+
super
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
def compatible_table_definition(t)
|
595
|
+
t
|
596
|
+
end
|
554
597
|
end
|
555
598
|
|
556
|
-
def self.inherited(subclass)
|
599
|
+
def self.inherited(subclass) # :nodoc:
|
557
600
|
super
|
558
601
|
if subclass.superclass == Migration
|
602
|
+
major = ActiveRecord::VERSION::MAJOR
|
603
|
+
minor = ActiveRecord::VERSION::MINOR
|
559
604
|
raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
|
560
|
-
"Please specify the
|
605
|
+
"Please specify the Active Record release the migration was written for:\n" \
|
561
606
|
"\n" \
|
562
|
-
" class #{subclass} < ActiveRecord::Migration[
|
607
|
+
" class #{subclass} < ActiveRecord::Migration[#{major}.#{minor}]"
|
563
608
|
end
|
564
609
|
end
|
565
610
|
|
@@ -571,10 +616,17 @@ module ActiveRecord
|
|
571
616
|
ActiveRecord::VERSION::STRING.to_f
|
572
617
|
end
|
573
618
|
|
574
|
-
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/
|
619
|
+
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
|
620
|
+
|
621
|
+
def self.valid_version_format?(version_string) # :nodoc:
|
622
|
+
[
|
623
|
+
MigrationFilenameRegexp,
|
624
|
+
/\A\d(_?\d)*\z/ # integer with optional underscores
|
625
|
+
].any? { |pattern| pattern.match?(version_string) }
|
626
|
+
end
|
575
627
|
|
576
628
|
# This class is used to verify that all migrations have been run before
|
577
|
-
# loading a web page if <tt>config.active_record.migration_error</tt> is set to
|
629
|
+
# loading a web page if <tt>config.active_record.migration_error</tt> is set to +:page_load+.
|
578
630
|
class CheckPending
|
579
631
|
def initialize(app, file_watcher: ActiveSupport::FileUpdateChecker)
|
580
632
|
@app = app
|
@@ -587,7 +639,7 @@ module ActiveRecord
|
|
587
639
|
@mutex.synchronize do
|
588
640
|
@watcher ||= build_watcher do
|
589
641
|
@needs_check = true
|
590
|
-
ActiveRecord::Migration.
|
642
|
+
ActiveRecord::Migration.check_pending_migrations
|
591
643
|
@needs_check = false
|
592
644
|
end
|
593
645
|
|
@@ -603,61 +655,84 @@ module ActiveRecord
|
|
603
655
|
|
604
656
|
private
|
605
657
|
def build_watcher(&block)
|
606
|
-
|
658
|
+
current_environment = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
659
|
+
all_configs = ActiveRecord::Base.configurations.configs_for(env_name: current_environment)
|
660
|
+
paths = all_configs.flat_map { |config| config.migrations_paths || Migrator.migrations_paths }.uniq
|
607
661
|
@file_watcher.new([], paths.index_with(["rb"]), &block)
|
608
662
|
end
|
609
663
|
|
610
664
|
def connection
|
611
|
-
ActiveRecord::
|
665
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
612
666
|
end
|
613
667
|
end
|
614
668
|
|
615
669
|
class << self
|
616
|
-
attr_accessor :delegate
|
617
|
-
attr_accessor :disable_ddl_transaction
|
670
|
+
attr_accessor :delegate # :nodoc:
|
671
|
+
attr_accessor :disable_ddl_transaction # :nodoc:
|
618
672
|
|
619
|
-
def nearest_delegate
|
673
|
+
def nearest_delegate # :nodoc:
|
620
674
|
delegate || superclass.nearest_delegate
|
621
675
|
end
|
622
676
|
|
623
|
-
# Raises
|
624
|
-
|
625
|
-
|
677
|
+
# Raises ActiveRecord::PendingMigrationError error if any migrations are pending.
|
678
|
+
#
|
679
|
+
# This is deprecated in favor of +check_all_pending!+
|
680
|
+
def check_pending!(connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection)
|
681
|
+
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
682
|
+
The `check_pending!` method is deprecated in favor of `check_all_pending!`. The
|
683
|
+
new implementation will loop through all available database configurations and find
|
684
|
+
pending migrations. The prior implementation did not permit this.
|
685
|
+
MSG
|
686
|
+
|
687
|
+
pending_migrations = connection.migration_context.open.pending_migrations
|
688
|
+
|
689
|
+
if pending_migrations.any?
|
690
|
+
raise ActiveRecord::PendingMigrationError.new(pending_migrations: pending_migrations)
|
691
|
+
end
|
626
692
|
end
|
627
693
|
|
628
|
-
|
629
|
-
|
630
|
-
|
694
|
+
# Raises ActiveRecord::PendingMigrationError error if any migrations are pending
|
695
|
+
# for all database configurations in an environment.
|
696
|
+
def check_all_pending!
|
697
|
+
pending_migrations = []
|
698
|
+
|
699
|
+
ActiveRecord::Tasks::DatabaseTasks.with_temporary_connection_for_each(env: env) do |connection|
|
700
|
+
if pending = connection.migration_context.open.pending_migrations
|
701
|
+
pending_migrations << pending
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
705
|
+
migrations = pending_migrations.flatten
|
631
706
|
|
632
|
-
|
633
|
-
|
707
|
+
if migrations.any?
|
708
|
+
raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
|
634
709
|
end
|
710
|
+
end
|
635
711
|
|
636
|
-
|
712
|
+
def load_schema_if_pending!
|
713
|
+
if any_schema_needs_update?
|
637
714
|
# Roundtrip to Rake to allow plugins to hook into database initialization.
|
638
715
|
root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
|
716
|
+
|
639
717
|
FileUtils.cd(root) do
|
640
|
-
Base.clear_all_connections!
|
718
|
+
Base.connection_handler.clear_all_connections!(:all)
|
641
719
|
system("bin/rails db:test:prepare")
|
642
720
|
end
|
643
721
|
end
|
644
722
|
|
645
|
-
|
646
|
-
Base.establish_connection(current_db_config)
|
647
|
-
|
648
|
-
check_pending!
|
723
|
+
check_pending_migrations
|
649
724
|
end
|
650
725
|
|
651
|
-
def maintain_test_schema!
|
652
|
-
if ActiveRecord
|
726
|
+
def maintain_test_schema! # :nodoc:
|
727
|
+
if ActiveRecord.maintain_test_schema
|
653
728
|
suppress_messages { load_schema_if_pending! }
|
654
729
|
end
|
655
730
|
end
|
656
731
|
|
657
|
-
def method_missing(name, *args, &block)
|
732
|
+
def method_missing(name, *args, &block) # :nodoc:
|
658
733
|
nearest_delegate.send(name, *args, &block)
|
659
734
|
end
|
660
|
-
ruby2_keywords(:method_missing)
|
735
|
+
ruby2_keywords(:method_missing)
|
661
736
|
|
662
737
|
def migrate(direction)
|
663
738
|
new.migrate direction
|
@@ -670,9 +745,44 @@ module ActiveRecord
|
|
670
745
|
def disable_ddl_transaction!
|
671
746
|
@disable_ddl_transaction = true
|
672
747
|
end
|
748
|
+
|
749
|
+
def check_pending_migrations # :nodoc:
|
750
|
+
migrations = pending_migrations
|
751
|
+
|
752
|
+
if migrations.any?
|
753
|
+
raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
private
|
758
|
+
def any_schema_needs_update?
|
759
|
+
!db_configs_in_current_env.all? do |db_config|
|
760
|
+
Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord.schema_format)
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
764
|
+
def db_configs_in_current_env
|
765
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env)
|
766
|
+
end
|
767
|
+
|
768
|
+
def pending_migrations
|
769
|
+
pending_migrations = []
|
770
|
+
|
771
|
+
ActiveRecord::Tasks::DatabaseTasks.with_temporary_connection_for_each(env: env) do |connection|
|
772
|
+
if pending = connection.migration_context.open.pending_migrations
|
773
|
+
pending_migrations << pending
|
774
|
+
end
|
775
|
+
end
|
776
|
+
|
777
|
+
pending_migrations.flatten
|
778
|
+
end
|
779
|
+
|
780
|
+
def env
|
781
|
+
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
782
|
+
end
|
673
783
|
end
|
674
784
|
|
675
|
-
def disable_ddl_transaction
|
785
|
+
def disable_ddl_transaction # :nodoc:
|
676
786
|
self.class.disable_ddl_transaction
|
677
787
|
end
|
678
788
|
|
@@ -685,6 +795,10 @@ module ActiveRecord
|
|
685
795
|
@connection = nil
|
686
796
|
end
|
687
797
|
|
798
|
+
def execution_strategy
|
799
|
+
@execution_strategy ||= ActiveRecord.migration_strategy.new(self)
|
800
|
+
end
|
801
|
+
|
688
802
|
self.verbose = true
|
689
803
|
# instantiate the delegate object after initialize is defined
|
690
804
|
self.delegate = new
|
@@ -696,7 +810,7 @@ module ActiveRecord
|
|
696
810
|
# and create the table 'apples' on the way up, and the reverse
|
697
811
|
# on the way down.
|
698
812
|
#
|
699
|
-
# class FixTLMigration < ActiveRecord::Migration[
|
813
|
+
# class FixTLMigration < ActiveRecord::Migration[7.1]
|
700
814
|
# def change
|
701
815
|
# revert do
|
702
816
|
# create_table(:horses) do |t|
|
@@ -715,7 +829,7 @@ module ActiveRecord
|
|
715
829
|
#
|
716
830
|
# require_relative "20121212123456_tenderlove_migration"
|
717
831
|
#
|
718
|
-
# class FixupTLMigration < ActiveRecord::Migration[
|
832
|
+
# class FixupTLMigration < ActiveRecord::Migration[7.1]
|
719
833
|
# def change
|
720
834
|
# revert TenderloveMigration
|
721
835
|
#
|
@@ -726,16 +840,16 @@ module ActiveRecord
|
|
726
840
|
# end
|
727
841
|
#
|
728
842
|
# This command can be nested.
|
729
|
-
def revert(*migration_classes)
|
843
|
+
def revert(*migration_classes, &block)
|
730
844
|
run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
|
731
845
|
if block_given?
|
732
846
|
if connection.respond_to? :revert
|
733
|
-
connection.revert
|
847
|
+
connection.revert(&block)
|
734
848
|
else
|
735
849
|
recorder = command_recorder
|
736
850
|
@connection = recorder
|
737
851
|
suppress_messages do
|
738
|
-
connection.revert
|
852
|
+
connection.revert(&block)
|
739
853
|
end
|
740
854
|
@connection = recorder.delegate
|
741
855
|
recorder.replay(self)
|
@@ -747,7 +861,7 @@ module ActiveRecord
|
|
747
861
|
connection.respond_to?(:reverting) && connection.reverting
|
748
862
|
end
|
749
863
|
|
750
|
-
ReversibleBlockHelper = Struct.new(:reverting) do
|
864
|
+
ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
|
751
865
|
def up
|
752
866
|
yield unless reverting
|
753
867
|
end
|
@@ -766,7 +880,7 @@ module ActiveRecord
|
|
766
880
|
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
|
767
881
|
# even when migrating down:
|
768
882
|
#
|
769
|
-
# class SplitNameMigration < ActiveRecord::Migration[
|
883
|
+
# class SplitNameMigration < ActiveRecord::Migration[7.1]
|
770
884
|
# def change
|
771
885
|
# add_column :users, :first_name, :string
|
772
886
|
# add_column :users, :last_name, :string
|
@@ -794,7 +908,7 @@ module ActiveRecord
|
|
794
908
|
# In the following example, the new column +published+ will be given
|
795
909
|
# the value +true+ for all existing records.
|
796
910
|
#
|
797
|
-
# class AddPublishedToPosts < ActiveRecord::Migration[
|
911
|
+
# class AddPublishedToPosts < ActiveRecord::Migration[7.1]
|
798
912
|
# def change
|
799
913
|
# add_column :posts, :published, :boolean, default: false
|
800
914
|
# up_only do
|
@@ -802,14 +916,15 @@ module ActiveRecord
|
|
802
916
|
# end
|
803
917
|
# end
|
804
918
|
# end
|
805
|
-
def up_only
|
806
|
-
execute_block
|
919
|
+
def up_only(&block)
|
920
|
+
execute_block(&block) unless reverting?
|
807
921
|
end
|
808
922
|
|
809
923
|
# Runs the given migration classes.
|
810
924
|
# Last argument can specify options:
|
811
|
-
#
|
812
|
-
# -
|
925
|
+
#
|
926
|
+
# - +:direction+ - Default is +:up+.
|
927
|
+
# - +:revert+ - Default is +false+.
|
813
928
|
def run(*migration_classes)
|
814
929
|
opts = migration_classes.extract_options!
|
815
930
|
dir = opts[:direction] || :up
|
@@ -846,7 +961,7 @@ module ActiveRecord
|
|
846
961
|
end
|
847
962
|
|
848
963
|
time = nil
|
849
|
-
ActiveRecord::
|
964
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection.pool.with_connection do |conn|
|
850
965
|
time = Benchmark.measure do
|
851
966
|
exec_migration(conn, direction)
|
852
967
|
end
|
@@ -871,6 +986,7 @@ module ActiveRecord
|
|
871
986
|
end
|
872
987
|
ensure
|
873
988
|
@connection = nil
|
989
|
+
@execution_strategy = nil
|
874
990
|
end
|
875
991
|
|
876
992
|
def write(text = "")
|
@@ -909,38 +1025,37 @@ module ActiveRecord
|
|
909
1025
|
end
|
910
1026
|
|
911
1027
|
def connection
|
912
|
-
@connection || ActiveRecord::
|
1028
|
+
@connection || ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
913
1029
|
end
|
914
1030
|
|
915
1031
|
def method_missing(method, *arguments, &block)
|
916
|
-
|
917
|
-
|
918
|
-
say_with_time "#{method}(#{arg_list})" do
|
1032
|
+
say_with_time "#{method}(#{format_arguments(arguments)})" do
|
919
1033
|
unless connection.respond_to? :revert
|
920
1034
|
unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
|
921
1035
|
arguments[0] = proper_table_name(arguments.first, table_name_options)
|
922
|
-
if
|
1036
|
+
if method == :rename_table ||
|
923
1037
|
(method == :remove_foreign_key && !arguments.second.is_a?(Hash))
|
924
1038
|
arguments[1] = proper_table_name(arguments.second, table_name_options)
|
925
1039
|
end
|
926
1040
|
end
|
927
1041
|
end
|
928
|
-
return super unless
|
929
|
-
|
1042
|
+
return super unless execution_strategy.respond_to?(method)
|
1043
|
+
execution_strategy.send(method, *arguments, &block)
|
930
1044
|
end
|
931
1045
|
end
|
932
|
-
ruby2_keywords(:method_missing)
|
1046
|
+
ruby2_keywords(:method_missing)
|
933
1047
|
|
934
1048
|
def copy(destination, sources, options = {})
|
935
1049
|
copied = []
|
936
|
-
schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
|
937
1050
|
|
938
1051
|
FileUtils.mkdir_p(destination) unless File.exist?(destination)
|
1052
|
+
schema_migration = SchemaMigration::NullSchemaMigration.new
|
1053
|
+
internal_metadata = InternalMetadata::NullInternalMetadata.new
|
939
1054
|
|
940
|
-
destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
|
1055
|
+
destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration, internal_metadata).migrations
|
941
1056
|
last = destination_migrations.last
|
942
1057
|
sources.each do |scope, path|
|
943
|
-
source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
|
1058
|
+
source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration, internal_metadata).migrations
|
944
1059
|
|
945
1060
|
source_migrations.each do |migration|
|
946
1061
|
source = File.binread(migration.filename)
|
@@ -955,6 +1070,12 @@ module ActiveRecord
|
|
955
1070
|
magic_comments << magic_comment; ""
|
956
1071
|
end || break
|
957
1072
|
end
|
1073
|
+
|
1074
|
+
if !magic_comments.empty? && source.start_with?("\n")
|
1075
|
+
magic_comments << "\n"
|
1076
|
+
source = source[1..-1]
|
1077
|
+
end
|
1078
|
+
|
958
1079
|
source = "#{magic_comments}#{inserted_comment}#{source}"
|
959
1080
|
|
960
1081
|
if duplicate = destination_migrations.detect { |m| m.name == migration.name }
|
@@ -992,16 +1113,16 @@ module ActiveRecord
|
|
992
1113
|
|
993
1114
|
# Determines the version number of the next migration.
|
994
1115
|
def next_migration_number(number)
|
995
|
-
if ActiveRecord
|
1116
|
+
if ActiveRecord.timestamped_migrations
|
996
1117
|
[Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
|
997
1118
|
else
|
998
|
-
|
1119
|
+
"%.3d" % number.to_i
|
999
1120
|
end
|
1000
1121
|
end
|
1001
1122
|
|
1002
1123
|
# Builds a hash for use in ActiveRecord::Migration#proper_table_name using
|
1003
1124
|
# the Active Record object's table_name prefix and suffix
|
1004
|
-
def table_name_options(config = ActiveRecord::Base)
|
1125
|
+
def table_name_options(config = ActiveRecord::Base) # :nodoc:
|
1005
1126
|
{
|
1006
1127
|
table_name_prefix: config.table_name_prefix,
|
1007
1128
|
table_name_suffix: config.table_name_suffix
|
@@ -1017,6 +1138,22 @@ module ActiveRecord
|
|
1017
1138
|
end
|
1018
1139
|
end
|
1019
1140
|
|
1141
|
+
def format_arguments(arguments)
|
1142
|
+
arg_list = arguments[0...-1].map(&:inspect)
|
1143
|
+
last_arg = arguments.last
|
1144
|
+
if last_arg.is_a?(Hash)
|
1145
|
+
last_arg = last_arg.reject { |k, _v| internal_option?(k) }
|
1146
|
+
arg_list << last_arg.inspect unless last_arg.empty?
|
1147
|
+
else
|
1148
|
+
arg_list << last_arg.inspect
|
1149
|
+
end
|
1150
|
+
arg_list.join(", ")
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
def internal_option?(option_name)
|
1154
|
+
option_name.start_with?("_")
|
1155
|
+
end
|
1156
|
+
|
1020
1157
|
def command_recorder
|
1021
1158
|
CommandRecorder.new(connection)
|
1022
1159
|
end
|
@@ -1042,19 +1179,66 @@ module ActiveRecord
|
|
1042
1179
|
end
|
1043
1180
|
|
1044
1181
|
def load_migration
|
1045
|
-
|
1182
|
+
Object.send(:remove_const, name) rescue nil
|
1183
|
+
|
1184
|
+
load(File.expand_path(filename))
|
1046
1185
|
name.constantize.new(name, version)
|
1047
1186
|
end
|
1048
1187
|
end
|
1049
1188
|
|
1050
|
-
|
1051
|
-
|
1189
|
+
# = \Migration \Context
|
1190
|
+
#
|
1191
|
+
# MigrationContext sets the context in which a migration is run.
|
1192
|
+
#
|
1193
|
+
# A migration context requires the path to the migrations is set
|
1194
|
+
# in the +migrations_paths+ parameter. Optionally a +schema_migration+
|
1195
|
+
# class can be provided. Multiple database applications will instantiate
|
1196
|
+
# a +SchemaMigration+ object per database. From the Rake tasks, \Rails will
|
1197
|
+
# handle this for you.
|
1198
|
+
class MigrationContext
|
1199
|
+
attr_reader :migrations_paths, :schema_migration, :internal_metadata
|
1200
|
+
|
1201
|
+
def initialize(migrations_paths, schema_migration = nil, internal_metadata = nil)
|
1202
|
+
if schema_migration == SchemaMigration
|
1203
|
+
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
1204
|
+
SchemaMigration no longer inherits from ActiveRecord::Base. If you want
|
1205
|
+
to use the default connection, remove this argument. If you want to use a
|
1206
|
+
specific connection, instantiate MigrationContext with the connection's schema
|
1207
|
+
migration, for example `MigrationContext.new(path, Dog.connection.schema_migration)`.
|
1208
|
+
MSG
|
1209
|
+
|
1210
|
+
schema_migration = nil
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
if internal_metadata == InternalMetadata
|
1214
|
+
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
1215
|
+
SchemaMigration no longer inherits from ActiveRecord::Base. If you want
|
1216
|
+
to use the default connection, remove this argument. If you want to use a
|
1217
|
+
specific connection, instantiate MigrationContext with the connection's internal
|
1218
|
+
metadata, for example `MigrationContext.new(path, nil, Dog.connection.internal_metadata)`.
|
1219
|
+
MSG
|
1220
|
+
|
1221
|
+
internal_metadata = nil
|
1222
|
+
end
|
1052
1223
|
|
1053
|
-
def initialize(migrations_paths, schema_migration)
|
1054
1224
|
@migrations_paths = migrations_paths
|
1055
|
-
@schema_migration = schema_migration
|
1225
|
+
@schema_migration = schema_migration || SchemaMigration.new(connection)
|
1226
|
+
@internal_metadata = internal_metadata || InternalMetadata.new(connection)
|
1056
1227
|
end
|
1057
1228
|
|
1229
|
+
# Runs the migrations in the +migrations_path+.
|
1230
|
+
#
|
1231
|
+
# If +target_version+ is +nil+, +migrate+ will run +up+.
|
1232
|
+
#
|
1233
|
+
# If the +current_version+ and +target_version+ are both
|
1234
|
+
# 0 then an empty array will be returned and no migrations
|
1235
|
+
# will be run.
|
1236
|
+
#
|
1237
|
+
# If the +current_version+ in the schema is greater than
|
1238
|
+
# the +target_version+, then +down+ will be run.
|
1239
|
+
#
|
1240
|
+
# If none of the conditions are met, +up+ will be run with
|
1241
|
+
# the +target_version+.
|
1058
1242
|
def migrate(target_version = nil, &block)
|
1059
1243
|
case
|
1060
1244
|
when target_version.nil?
|
@@ -1068,64 +1252,64 @@ module ActiveRecord
|
|
1068
1252
|
end
|
1069
1253
|
end
|
1070
1254
|
|
1071
|
-
def rollback(steps = 1)
|
1255
|
+
def rollback(steps = 1) # :nodoc:
|
1072
1256
|
move(:down, steps)
|
1073
1257
|
end
|
1074
1258
|
|
1075
|
-
def forward(steps = 1)
|
1259
|
+
def forward(steps = 1) # :nodoc:
|
1076
1260
|
move(:up, steps)
|
1077
1261
|
end
|
1078
1262
|
|
1079
|
-
def up(target_version = nil)
|
1263
|
+
def up(target_version = nil, &block) # :nodoc:
|
1080
1264
|
selected_migrations = if block_given?
|
1081
|
-
migrations.select
|
1265
|
+
migrations.select(&block)
|
1082
1266
|
else
|
1083
1267
|
migrations
|
1084
1268
|
end
|
1085
1269
|
|
1086
|
-
Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
|
1270
|
+
Migrator.new(:up, selected_migrations, schema_migration, internal_metadata, target_version).migrate
|
1087
1271
|
end
|
1088
1272
|
|
1089
|
-
def down(target_version = nil)
|
1273
|
+
def down(target_version = nil, &block) # :nodoc:
|
1090
1274
|
selected_migrations = if block_given?
|
1091
|
-
migrations.select
|
1275
|
+
migrations.select(&block)
|
1092
1276
|
else
|
1093
1277
|
migrations
|
1094
1278
|
end
|
1095
1279
|
|
1096
|
-
Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
|
1280
|
+
Migrator.new(:down, selected_migrations, schema_migration, internal_metadata, target_version).migrate
|
1097
1281
|
end
|
1098
1282
|
|
1099
|
-
def run(direction, target_version)
|
1100
|
-
Migrator.new(direction, migrations, schema_migration, target_version).run
|
1283
|
+
def run(direction, target_version) # :nodoc:
|
1284
|
+
Migrator.new(direction, migrations, schema_migration, internal_metadata, target_version).run
|
1101
1285
|
end
|
1102
1286
|
|
1103
|
-
def open
|
1104
|
-
Migrator.new(:up, migrations, schema_migration)
|
1287
|
+
def open # :nodoc:
|
1288
|
+
Migrator.new(:up, migrations, schema_migration, internal_metadata)
|
1105
1289
|
end
|
1106
1290
|
|
1107
|
-
def get_all_versions
|
1291
|
+
def get_all_versions # :nodoc:
|
1108
1292
|
if schema_migration.table_exists?
|
1109
|
-
schema_migration.
|
1293
|
+
schema_migration.integer_versions
|
1110
1294
|
else
|
1111
1295
|
[]
|
1112
1296
|
end
|
1113
1297
|
end
|
1114
1298
|
|
1115
|
-
def current_version
|
1299
|
+
def current_version # :nodoc:
|
1116
1300
|
get_all_versions.max || 0
|
1117
1301
|
rescue ActiveRecord::NoDatabaseError
|
1118
1302
|
end
|
1119
1303
|
|
1120
|
-
def needs_migration?
|
1121
|
-
|
1304
|
+
def needs_migration? # :nodoc:
|
1305
|
+
pending_migration_versions.size > 0
|
1122
1306
|
end
|
1123
1307
|
|
1124
|
-
def
|
1125
|
-
migrations.
|
1308
|
+
def pending_migration_versions # :nodoc:
|
1309
|
+
migrations.collect(&:version) - get_all_versions
|
1126
1310
|
end
|
1127
1311
|
|
1128
|
-
def migrations
|
1312
|
+
def migrations # :nodoc:
|
1129
1313
|
migrations = migration_files.map do |file|
|
1130
1314
|
version, name, scope = parse_migration_filename(file)
|
1131
1315
|
raise IllegalMigrationNameError.new(file) unless version
|
@@ -1138,43 +1322,47 @@ module ActiveRecord
|
|
1138
1322
|
migrations.sort_by(&:version)
|
1139
1323
|
end
|
1140
1324
|
|
1141
|
-
def migrations_status
|
1325
|
+
def migrations_status # :nodoc:
|
1142
1326
|
db_list = schema_migration.normalized_versions
|
1143
1327
|
|
1144
|
-
file_list = migration_files.
|
1328
|
+
file_list = migration_files.filter_map do |file|
|
1145
1329
|
version, name, scope = parse_migration_filename(file)
|
1146
1330
|
raise IllegalMigrationNameError.new(file) unless version
|
1147
1331
|
version = schema_migration.normalize_migration_number(version)
|
1148
1332
|
status = db_list.delete(version) ? "up" : "down"
|
1149
1333
|
[status, version, (name + scope).humanize]
|
1150
|
-
end
|
1334
|
+
end
|
1151
1335
|
|
1152
1336
|
db_list.map! do |version|
|
1153
1337
|
["up", version, "********** NO FILE **********"]
|
1154
1338
|
end
|
1155
1339
|
|
1156
|
-
(db_list + file_list).sort_by { |_, version, _| version }
|
1340
|
+
(db_list + file_list).sort_by { |_, version, _| version.to_i }
|
1157
1341
|
end
|
1158
1342
|
|
1159
|
-
def current_environment
|
1343
|
+
def current_environment # :nodoc:
|
1160
1344
|
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
1161
1345
|
end
|
1162
1346
|
|
1163
|
-
def protected_environment?
|
1347
|
+
def protected_environment? # :nodoc:
|
1164
1348
|
ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
|
1165
1349
|
end
|
1166
1350
|
|
1167
|
-
def last_stored_environment
|
1168
|
-
return nil unless
|
1351
|
+
def last_stored_environment # :nodoc:
|
1352
|
+
return nil unless connection.internal_metadata.enabled?
|
1169
1353
|
return nil if current_version == 0
|
1170
|
-
raise NoEnvironmentInSchemaError unless
|
1354
|
+
raise NoEnvironmentInSchemaError unless connection.internal_metadata.table_exists?
|
1171
1355
|
|
1172
|
-
environment =
|
1356
|
+
environment = connection.internal_metadata[:environment]
|
1173
1357
|
raise NoEnvironmentInSchemaError unless environment
|
1174
1358
|
environment
|
1175
1359
|
end
|
1176
1360
|
|
1177
1361
|
private
|
1362
|
+
def connection
|
1363
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1364
|
+
end
|
1365
|
+
|
1178
1366
|
def migration_files
|
1179
1367
|
paths = Array(migrations_paths)
|
1180
1368
|
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
@@ -1185,7 +1373,7 @@ module ActiveRecord
|
|
1185
1373
|
end
|
1186
1374
|
|
1187
1375
|
def move(direction, steps)
|
1188
|
-
migrator = Migrator.new(direction, migrations, schema_migration)
|
1376
|
+
migrator = Migrator.new(direction, migrations, schema_migration, internal_metadata)
|
1189
1377
|
|
1190
1378
|
if current_version != 0 && !migrator.current_migration
|
1191
1379
|
raise UnknownMigrationVersionError.new(current_version)
|
@@ -1210,23 +1398,28 @@ module ActiveRecord
|
|
1210
1398
|
|
1211
1399
|
# For cases where a table doesn't exist like loading from schema cache
|
1212
1400
|
def current_version
|
1213
|
-
|
1401
|
+
connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1402
|
+
schema_migration = SchemaMigration.new(connection)
|
1403
|
+
internal_metadata = InternalMetadata.new(connection)
|
1404
|
+
|
1405
|
+
MigrationContext.new(migrations_paths, schema_migration, internal_metadata).current_version
|
1214
1406
|
end
|
1215
1407
|
end
|
1216
1408
|
|
1217
1409
|
self.migrations_paths = ["db/migrate"]
|
1218
1410
|
|
1219
|
-
def initialize(direction, migrations, schema_migration, target_version = nil)
|
1411
|
+
def initialize(direction, migrations, schema_migration, internal_metadata, target_version = nil)
|
1220
1412
|
@direction = direction
|
1221
1413
|
@target_version = target_version
|
1222
1414
|
@migrated_versions = nil
|
1223
1415
|
@migrations = migrations
|
1224
1416
|
@schema_migration = schema_migration
|
1417
|
+
@internal_metadata = internal_metadata
|
1225
1418
|
|
1226
1419
|
validate(@migrations)
|
1227
1420
|
|
1228
1421
|
@schema_migration.create_table
|
1229
|
-
|
1422
|
+
@internal_metadata.create_table
|
1230
1423
|
end
|
1231
1424
|
|
1232
1425
|
def current_version
|
@@ -1279,18 +1472,21 @@ module ActiveRecord
|
|
1279
1472
|
end
|
1280
1473
|
|
1281
1474
|
def load_migrated
|
1282
|
-
@migrated_versions = Set.new(@schema_migration.
|
1475
|
+
@migrated_versions = Set.new(@schema_migration.integer_versions)
|
1283
1476
|
end
|
1284
1477
|
|
1285
1478
|
private
|
1479
|
+
def connection
|
1480
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1481
|
+
end
|
1482
|
+
|
1286
1483
|
# Used for running a specific migration.
|
1287
1484
|
def run_without_lock
|
1288
1485
|
migration = migrations.detect { |m| m.version == @target_version }
|
1289
1486
|
raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
|
1290
|
-
result = execute_migration_in_transaction(migration)
|
1291
1487
|
|
1292
1488
|
record_environment
|
1293
|
-
|
1489
|
+
execute_migration_in_transaction(migration)
|
1294
1490
|
end
|
1295
1491
|
|
1296
1492
|
# Used for running multiple migrations up to or down to a certain value.
|
@@ -1299,15 +1495,15 @@ module ActiveRecord
|
|
1299
1495
|
raise UnknownMigrationVersionError.new(@target_version)
|
1300
1496
|
end
|
1301
1497
|
|
1302
|
-
result = runnable.each(&method(:execute_migration_in_transaction))
|
1303
1498
|
record_environment
|
1304
|
-
|
1499
|
+
runnable.each(&method(:execute_migration_in_transaction))
|
1305
1500
|
end
|
1306
1501
|
|
1307
1502
|
# Stores the current environment in the database.
|
1308
1503
|
def record_environment
|
1309
1504
|
return if down?
|
1310
|
-
|
1505
|
+
|
1506
|
+
@internal_metadata[:environment] = connection.pool.db_config.env_name
|
1311
1507
|
end
|
1312
1508
|
|
1313
1509
|
def ran?(migration)
|
@@ -1359,10 +1555,10 @@ module ActiveRecord
|
|
1359
1555
|
def record_version_state_after_migrating(version)
|
1360
1556
|
if down?
|
1361
1557
|
migrated.delete(version)
|
1362
|
-
@schema_migration.
|
1558
|
+
@schema_migration.delete_version(version.to_s)
|
1363
1559
|
else
|
1364
1560
|
migrated << version
|
1365
|
-
@schema_migration.
|
1561
|
+
@schema_migration.create_version(version.to_s)
|
1366
1562
|
end
|
1367
1563
|
end
|
1368
1564
|
|
@@ -1375,52 +1571,40 @@ module ActiveRecord
|
|
1375
1571
|
end
|
1376
1572
|
|
1377
1573
|
# Wrap the migration in a transaction only if supported by the adapter.
|
1378
|
-
def ddl_transaction(migration)
|
1574
|
+
def ddl_transaction(migration, &block)
|
1379
1575
|
if use_transaction?(migration)
|
1380
|
-
|
1576
|
+
connection.transaction(&block)
|
1381
1577
|
else
|
1382
1578
|
yield
|
1383
1579
|
end
|
1384
1580
|
end
|
1385
1581
|
|
1386
1582
|
def use_transaction?(migration)
|
1387
|
-
!migration.disable_ddl_transaction &&
|
1583
|
+
!migration.disable_ddl_transaction && connection.supports_ddl_transactions?
|
1388
1584
|
end
|
1389
1585
|
|
1390
1586
|
def use_advisory_lock?
|
1391
|
-
|
1587
|
+
connection.advisory_locks_enabled?
|
1392
1588
|
end
|
1393
1589
|
|
1394
1590
|
def with_advisory_lock
|
1395
1591
|
lock_id = generate_migrator_advisory_lock_id
|
1396
1592
|
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
yield
|
1402
|
-
ensure
|
1403
|
-
if got_lock && !connection.release_advisory_lock(lock_id)
|
1404
|
-
raise ConcurrentMigrationError.new(
|
1405
|
-
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
1406
|
-
)
|
1407
|
-
end
|
1408
|
-
end
|
1409
|
-
end
|
1410
|
-
|
1411
|
-
def with_advisory_lock_connection
|
1412
|
-
pool = ActiveRecord::ConnectionAdapters::ConnectionHandler.new.establish_connection(
|
1413
|
-
ActiveRecord::Base.connection_db_config
|
1414
|
-
)
|
1415
|
-
|
1416
|
-
pool.with_connection { |connection| yield(connection) }
|
1593
|
+
got_lock = connection.get_advisory_lock(lock_id)
|
1594
|
+
raise ConcurrentMigrationError unless got_lock
|
1595
|
+
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
1596
|
+
yield
|
1417
1597
|
ensure
|
1418
|
-
|
1598
|
+
if got_lock && !connection.release_advisory_lock(lock_id)
|
1599
|
+
raise ConcurrentMigrationError.new(
|
1600
|
+
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
1601
|
+
)
|
1602
|
+
end
|
1419
1603
|
end
|
1420
1604
|
|
1421
1605
|
MIGRATOR_SALT = 2053462845
|
1422
1606
|
def generate_migrator_advisory_lock_id
|
1423
|
-
db_name_hash = Zlib.crc32(
|
1607
|
+
db_name_hash = Zlib.crc32(connection.current_database)
|
1424
1608
|
MIGRATOR_SALT * db_name_hash
|
1425
1609
|
end
|
1426
1610
|
end
|