activerecord 7.0.0 → 7.1.2
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 +1701 -1039
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -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 +362 -236
- 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 +52 -34
- 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 +129 -31
- 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 -131
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +513 -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 +151 -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 +16 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -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/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +4 -2
- 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 +372 -63
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +359 -197
- 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 +52 -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 +99 -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 +142 -153
- 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 -86
- 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 +113 -29
- 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 +3 -3
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +57 -10
- data/lib/active_record/integration.rb +10 -10
- data/lib/active_record/internal_metadata.rb +120 -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 +108 -10
- 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/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +274 -117
- data/lib/active_record/model_schema.rb +86 -54
- data/lib/active_record/nested_attributes.rb +24 -6
- data/lib/active_record/normalization.rb +167 -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 +128 -62
- data/lib/active_record/railties/controller_runtime.rb +12 -8
- data/lib/active_record/railties/databases.rake +145 -146
- 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 +189 -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 +208 -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 +430 -77
- 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 +27 -15
- 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 +1 -9
- 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 +51 -15
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -7,6 +7,7 @@ require "active_support/core_ext/array/access"
|
|
7
7
|
require "active_support/core_ext/enumerable"
|
8
8
|
require "active_support/core_ext/module/attribute_accessors"
|
9
9
|
require "active_support/actionable_error"
|
10
|
+
require "active_record/migration/pending_migration_connection"
|
10
11
|
|
11
12
|
module ActiveRecord
|
12
13
|
class MigrationError < ActiveRecordError # :nodoc:
|
@@ -20,7 +21,7 @@ module ActiveRecord
|
|
20
21
|
# For example the following migration is not reversible.
|
21
22
|
# Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
|
22
23
|
#
|
23
|
-
# class IrreversibleMigrationExample < ActiveRecord::Migration[7.
|
24
|
+
# class IrreversibleMigrationExample < ActiveRecord::Migration[7.1]
|
24
25
|
# def change
|
25
26
|
# create_table :distributors do |t|
|
26
27
|
# t.string :zipcode
|
@@ -38,7 +39,7 @@ module ActiveRecord
|
|
38
39
|
#
|
39
40
|
# 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
|
40
41
|
#
|
41
|
-
# class ReversibleMigrationExample < ActiveRecord::Migration[7.
|
42
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[7.1]
|
42
43
|
# def up
|
43
44
|
# create_table :distributors do |t|
|
44
45
|
# t.string :zipcode
|
@@ -63,7 +64,7 @@ module ActiveRecord
|
|
63
64
|
#
|
64
65
|
# 2. Use the #reversible method in <tt>#change</tt> method:
|
65
66
|
#
|
66
|
-
# class ReversibleMigrationExample < ActiveRecord::Migration[7.
|
67
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[7.1]
|
67
68
|
# def change
|
68
69
|
# create_table :distributors do |t|
|
69
70
|
# t.string :zipcode
|
@@ -137,32 +138,38 @@ module ActiveRecord
|
|
137
138
|
ActiveRecord::Tasks::DatabaseTasks.migrate
|
138
139
|
|
139
140
|
if ActiveRecord.dump_schema_after_migration
|
140
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
141
|
-
|
142
|
-
)
|
141
|
+
connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
142
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(connection.pool.db_config)
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
-
def initialize(message = nil)
|
147
|
-
|
146
|
+
def initialize(message = nil, pending_migrations: nil)
|
147
|
+
if pending_migrations.nil?
|
148
|
+
connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
149
|
+
pending_migrations = connection.migration_context.open.pending_migrations
|
150
|
+
end
|
151
|
+
|
152
|
+
super(message || detailed_migration_message(pending_migrations))
|
148
153
|
end
|
149
154
|
|
150
155
|
private
|
151
|
-
def detailed_migration_message
|
156
|
+
def detailed_migration_message(pending_migrations)
|
152
157
|
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)
|
158
|
+
message += " RAILS_ENV=#{::Rails.env}" if defined?(Rails.env) && !Rails.env.local?
|
154
159
|
message += "\n\n"
|
155
160
|
|
156
|
-
pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
|
157
|
-
|
158
161
|
message += "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}\n\n"
|
159
162
|
|
160
163
|
pending_migrations.each do |pending_migration|
|
161
|
-
message += "#{pending_migration.
|
164
|
+
message += "#{pending_migration.filename}\n"
|
162
165
|
end
|
163
166
|
|
164
167
|
message
|
165
168
|
end
|
169
|
+
|
170
|
+
def connection
|
171
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
172
|
+
end
|
166
173
|
end
|
167
174
|
|
168
175
|
class ConcurrentMigrationError < MigrationError # :nodoc:
|
@@ -228,7 +235,7 @@ module ActiveRecord
|
|
228
235
|
#
|
229
236
|
# Example of a simple migration:
|
230
237
|
#
|
231
|
-
# class AddSsl < ActiveRecord::Migration[7.
|
238
|
+
# class AddSsl < ActiveRecord::Migration[7.1]
|
232
239
|
# def up
|
233
240
|
# add_column :accounts, :ssl_enabled, :boolean, default: true
|
234
241
|
# end
|
@@ -248,7 +255,7 @@ module ActiveRecord
|
|
248
255
|
#
|
249
256
|
# Example of a more complex migration that also needs to initialize data:
|
250
257
|
#
|
251
|
-
# class AddSystemSettings < ActiveRecord::Migration[7.
|
258
|
+
# class AddSystemSettings < ActiveRecord::Migration[7.1]
|
252
259
|
# def up
|
253
260
|
# create_table :system_settings do |t|
|
254
261
|
# t.string :name
|
@@ -326,7 +333,7 @@ module ActiveRecord
|
|
326
333
|
# details.
|
327
334
|
# * <tt>change_table(name, options)</tt>: Allows to make column alterations to
|
328
335
|
# 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.
|
336
|
+
# can then add/remove columns, indexes, or foreign keys to it.
|
330
337
|
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
|
331
338
|
# a column but keeps the type and content.
|
332
339
|
# * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
|
@@ -356,12 +363,12 @@ module ActiveRecord
|
|
356
363
|
# == Irreversible transformations
|
357
364
|
#
|
358
365
|
# Some transformations are destructive in a manner that cannot be reversed.
|
359
|
-
# Migrations of that kind should raise an
|
366
|
+
# Migrations of that kind should raise an ActiveRecord::IrreversibleMigration
|
360
367
|
# exception in their +down+ method.
|
361
368
|
#
|
362
|
-
# == Running migrations from within Rails
|
369
|
+
# == Running migrations from within \Rails
|
363
370
|
#
|
364
|
-
# The Rails package has several tools to help create and apply migrations.
|
371
|
+
# The \Rails package has several tools to help create and apply migrations.
|
365
372
|
#
|
366
373
|
# To generate a new migration, you can use
|
367
374
|
# bin/rails generate migration MyNewMigration
|
@@ -376,7 +383,7 @@ module ActiveRecord
|
|
376
383
|
# bin/rails generate migration add_fieldname_to_tablename fieldname:string
|
377
384
|
#
|
378
385
|
# This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
|
379
|
-
# class AddFieldnameToTablename < ActiveRecord::Migration[7.
|
386
|
+
# class AddFieldnameToTablename < ActiveRecord::Migration[7.1]
|
380
387
|
# def change
|
381
388
|
# add_column :tablenames, :fieldname, :string
|
382
389
|
# end
|
@@ -395,14 +402,14 @@ module ActiveRecord
|
|
395
402
|
# wish to rollback last few migrations. <tt>bin/rails db:rollback STEP=2</tt> will rollback
|
396
403
|
# the latest two migrations.
|
397
404
|
#
|
398
|
-
# If any of the migrations throw an
|
405
|
+
# If any of the migrations throw an ActiveRecord::IrreversibleMigration exception,
|
399
406
|
# that step will fail and you'll have some manual work to do.
|
400
407
|
#
|
401
408
|
# == More examples
|
402
409
|
#
|
403
410
|
# Not all migrations change the schema. Some just fix the data:
|
404
411
|
#
|
405
|
-
# class RemoveEmptyTags < ActiveRecord::Migration[7.
|
412
|
+
# class RemoveEmptyTags < ActiveRecord::Migration[7.1]
|
406
413
|
# def up
|
407
414
|
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
|
408
415
|
# end
|
@@ -415,7 +422,7 @@ module ActiveRecord
|
|
415
422
|
#
|
416
423
|
# Others remove columns when they migrate up instead of down:
|
417
424
|
#
|
418
|
-
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.
|
425
|
+
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.1]
|
419
426
|
# def up
|
420
427
|
# remove_column :items, :incomplete_items_count
|
421
428
|
# remove_column :items, :completed_items_count
|
@@ -429,7 +436,7 @@ module ActiveRecord
|
|
429
436
|
#
|
430
437
|
# And sometimes you need to do something in SQL not abstracted directly by migrations:
|
431
438
|
#
|
432
|
-
# class MakeJoinUnique < ActiveRecord::Migration[7.
|
439
|
+
# class MakeJoinUnique < ActiveRecord::Migration[7.1]
|
433
440
|
# def up
|
434
441
|
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
|
435
442
|
# end
|
@@ -446,7 +453,7 @@ module ActiveRecord
|
|
446
453
|
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
|
447
454
|
# latest column data from after the new column was added. Example:
|
448
455
|
#
|
449
|
-
# class AddPeopleSalary < ActiveRecord::Migration[7.
|
456
|
+
# class AddPeopleSalary < ActiveRecord::Migration[7.1]
|
450
457
|
# def up
|
451
458
|
# add_column :people, :salary, :integer
|
452
459
|
# Person.reset_column_information
|
@@ -482,7 +489,7 @@ module ActiveRecord
|
|
482
489
|
#
|
483
490
|
# == Timestamped Migrations
|
484
491
|
#
|
485
|
-
# By default, Rails generates migrations that look like:
|
492
|
+
# By default, \Rails generates migrations that look like:
|
486
493
|
#
|
487
494
|
# 20080717013526_your_migration_name.rb
|
488
495
|
#
|
@@ -504,7 +511,7 @@ module ActiveRecord
|
|
504
511
|
# To define a reversible migration, define the +change+ method in your
|
505
512
|
# migration like this:
|
506
513
|
#
|
507
|
-
# class TenderloveMigration < ActiveRecord::Migration[7.
|
514
|
+
# class TenderloveMigration < ActiveRecord::Migration[7.1]
|
508
515
|
# def change
|
509
516
|
# create_table(:horses) do |t|
|
510
517
|
# t.column :content, :text
|
@@ -521,11 +528,11 @@ module ActiveRecord
|
|
521
528
|
# as before.
|
522
529
|
#
|
523
530
|
# If a command cannot be reversed, an
|
524
|
-
#
|
531
|
+
# ActiveRecord::IrreversibleMigration exception will be raised when
|
525
532
|
# the migration is moving down.
|
526
533
|
#
|
527
534
|
# For a list of commands that are reversible, please see
|
528
|
-
#
|
535
|
+
# +ActiveRecord::Migration::CommandRecorder+.
|
529
536
|
#
|
530
537
|
# == Transactional Migrations
|
531
538
|
#
|
@@ -534,7 +541,7 @@ module ActiveRecord
|
|
534
541
|
# can't execute inside a transaction though, and for these situations
|
535
542
|
# you can turn the automatic transactions off.
|
536
543
|
#
|
537
|
-
# class ChangeEnum < ActiveRecord::Migration[7.
|
544
|
+
# class ChangeEnum < ActiveRecord::Migration[7.1]
|
538
545
|
# disable_ddl_transaction!
|
539
546
|
#
|
540
547
|
# def up
|
@@ -548,9 +555,46 @@ module ActiveRecord
|
|
548
555
|
autoload :CommandRecorder, "active_record/migration/command_recorder"
|
549
556
|
autoload :Compatibility, "active_record/migration/compatibility"
|
550
557
|
autoload :JoinTable, "active_record/migration/join_table"
|
558
|
+
autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
|
559
|
+
autoload :DefaultStrategy, "active_record/migration/default_strategy"
|
551
560
|
|
552
561
|
# This must be defined before the inherited hook, below
|
553
562
|
class Current < Migration # :nodoc:
|
563
|
+
def create_table(table_name, **options)
|
564
|
+
if block_given?
|
565
|
+
super { |t| yield compatible_table_definition(t) }
|
566
|
+
else
|
567
|
+
super
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
def change_table(table_name, **options)
|
572
|
+
if block_given?
|
573
|
+
super { |t| yield compatible_table_definition(t) }
|
574
|
+
else
|
575
|
+
super
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
def create_join_table(table_1, table_2, **options)
|
580
|
+
if block_given?
|
581
|
+
super { |t| yield compatible_table_definition(t) }
|
582
|
+
else
|
583
|
+
super
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
def drop_table(table_name, **options)
|
588
|
+
if block_given?
|
589
|
+
super { |t| yield compatible_table_definition(t) }
|
590
|
+
else
|
591
|
+
super
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
def compatible_table_definition(t)
|
596
|
+
t
|
597
|
+
end
|
554
598
|
end
|
555
599
|
|
556
600
|
def self.inherited(subclass) # :nodoc:
|
@@ -575,8 +619,15 @@ module ActiveRecord
|
|
575
619
|
|
576
620
|
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
|
577
621
|
|
622
|
+
def self.valid_version_format?(version_string) # :nodoc:
|
623
|
+
[
|
624
|
+
MigrationFilenameRegexp,
|
625
|
+
/\A\d(_?\d)*\z/ # integer with optional underscores
|
626
|
+
].any? { |pattern| pattern.match?(version_string) }
|
627
|
+
end
|
628
|
+
|
578
629
|
# This class is used to verify that all migrations have been run before
|
579
|
-
# loading a web page if <tt>config.active_record.migration_error</tt> is set to
|
630
|
+
# loading a web page if <tt>config.active_record.migration_error</tt> is set to +:page_load+.
|
580
631
|
class CheckPending
|
581
632
|
def initialize(app, file_watcher: ActiveSupport::FileUpdateChecker)
|
582
633
|
@app = app
|
@@ -589,7 +640,7 @@ module ActiveRecord
|
|
589
640
|
@mutex.synchronize do
|
590
641
|
@watcher ||= build_watcher do
|
591
642
|
@needs_check = true
|
592
|
-
ActiveRecord::Migration.
|
643
|
+
ActiveRecord::Migration.check_pending_migrations
|
593
644
|
@needs_check = false
|
594
645
|
end
|
595
646
|
|
@@ -605,12 +656,14 @@ module ActiveRecord
|
|
605
656
|
|
606
657
|
private
|
607
658
|
def build_watcher(&block)
|
608
|
-
|
659
|
+
current_environment = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
660
|
+
all_configs = ActiveRecord::Base.configurations.configs_for(env_name: current_environment)
|
661
|
+
paths = all_configs.flat_map { |config| config.migrations_paths || Migrator.migrations_paths }.uniq
|
609
662
|
@file_watcher.new([], paths.index_with(["rb"]), &block)
|
610
663
|
end
|
611
664
|
|
612
665
|
def connection
|
613
|
-
ActiveRecord::
|
666
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
614
667
|
end
|
615
668
|
end
|
616
669
|
|
@@ -622,32 +675,53 @@ module ActiveRecord
|
|
622
675
|
delegate || superclass.nearest_delegate
|
623
676
|
end
|
624
677
|
|
625
|
-
# Raises
|
626
|
-
|
627
|
-
|
678
|
+
# Raises ActiveRecord::PendingMigrationError error if any migrations are pending.
|
679
|
+
#
|
680
|
+
# This is deprecated in favor of +check_all_pending!+
|
681
|
+
def check_pending!(connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection)
|
682
|
+
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
683
|
+
The `check_pending!` method is deprecated in favor of `check_all_pending!`. The
|
684
|
+
new implementation will loop through all available database configurations and find
|
685
|
+
pending migrations. The prior implementation did not permit this.
|
686
|
+
MSG
|
687
|
+
|
688
|
+
pending_migrations = connection.migration_context.open.pending_migrations
|
689
|
+
|
690
|
+
if pending_migrations.any?
|
691
|
+
raise ActiveRecord::PendingMigrationError.new(pending_migrations: pending_migrations)
|
692
|
+
end
|
628
693
|
end
|
629
694
|
|
630
|
-
|
631
|
-
|
632
|
-
|
695
|
+
# Raises ActiveRecord::PendingMigrationError error if any migrations are pending
|
696
|
+
# for all database configurations in an environment.
|
697
|
+
def check_all_pending!
|
698
|
+
pending_migrations = []
|
633
699
|
|
634
|
-
|
635
|
-
|
700
|
+
ActiveRecord::Tasks::DatabaseTasks.with_temporary_connection_for_each(env: env) do |connection|
|
701
|
+
if pending = connection.migration_context.open.pending_migrations
|
702
|
+
pending_migrations << pending
|
703
|
+
end
|
636
704
|
end
|
637
705
|
|
638
|
-
|
706
|
+
migrations = pending_migrations.flatten
|
707
|
+
|
708
|
+
if migrations.any?
|
709
|
+
raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
def load_schema_if_pending!
|
714
|
+
if any_schema_needs_update?
|
639
715
|
# Roundtrip to Rake to allow plugins to hook into database initialization.
|
640
716
|
root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
|
717
|
+
|
641
718
|
FileUtils.cd(root) do
|
642
|
-
Base.clear_all_connections!
|
719
|
+
Base.connection_handler.clear_all_connections!(:all)
|
643
720
|
system("bin/rails db:test:prepare")
|
644
721
|
end
|
645
722
|
end
|
646
723
|
|
647
|
-
|
648
|
-
Base.establish_connection(current_db_config)
|
649
|
-
|
650
|
-
check_pending!
|
724
|
+
check_pending_migrations
|
651
725
|
end
|
652
726
|
|
653
727
|
def maintain_test_schema! # :nodoc:
|
@@ -672,6 +746,43 @@ module ActiveRecord
|
|
672
746
|
def disable_ddl_transaction!
|
673
747
|
@disable_ddl_transaction = true
|
674
748
|
end
|
749
|
+
|
750
|
+
def check_pending_migrations # :nodoc:
|
751
|
+
migrations = pending_migrations
|
752
|
+
|
753
|
+
if migrations.any?
|
754
|
+
raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
758
|
+
private
|
759
|
+
def any_schema_needs_update?
|
760
|
+
!db_configs_in_current_env.all? do |db_config|
|
761
|
+
Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord.schema_format)
|
762
|
+
end
|
763
|
+
end
|
764
|
+
|
765
|
+
def db_configs_in_current_env
|
766
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env)
|
767
|
+
end
|
768
|
+
|
769
|
+
def pending_migrations
|
770
|
+
pending_migrations = []
|
771
|
+
|
772
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
|
773
|
+
ActiveRecord::PendingMigrationConnection.establish_temporary_connection(db_config) do |conn|
|
774
|
+
if pending = conn.migration_context.open.pending_migrations
|
775
|
+
pending_migrations << pending
|
776
|
+
end
|
777
|
+
end
|
778
|
+
end
|
779
|
+
|
780
|
+
pending_migrations.flatten
|
781
|
+
end
|
782
|
+
|
783
|
+
def env
|
784
|
+
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
785
|
+
end
|
675
786
|
end
|
676
787
|
|
677
788
|
def disable_ddl_transaction # :nodoc:
|
@@ -687,6 +798,10 @@ module ActiveRecord
|
|
687
798
|
@connection = nil
|
688
799
|
end
|
689
800
|
|
801
|
+
def execution_strategy
|
802
|
+
@execution_strategy ||= ActiveRecord.migration_strategy.new(self)
|
803
|
+
end
|
804
|
+
|
690
805
|
self.verbose = true
|
691
806
|
# instantiate the delegate object after initialize is defined
|
692
807
|
self.delegate = new
|
@@ -698,7 +813,7 @@ module ActiveRecord
|
|
698
813
|
# and create the table 'apples' on the way up, and the reverse
|
699
814
|
# on the way down.
|
700
815
|
#
|
701
|
-
# class FixTLMigration < ActiveRecord::Migration[7.
|
816
|
+
# class FixTLMigration < ActiveRecord::Migration[7.1]
|
702
817
|
# def change
|
703
818
|
# revert do
|
704
819
|
# create_table(:horses) do |t|
|
@@ -717,7 +832,7 @@ module ActiveRecord
|
|
717
832
|
#
|
718
833
|
# require_relative "20121212123456_tenderlove_migration"
|
719
834
|
#
|
720
|
-
# class FixupTLMigration < ActiveRecord::Migration[7.
|
835
|
+
# class FixupTLMigration < ActiveRecord::Migration[7.1]
|
721
836
|
# def change
|
722
837
|
# revert TenderloveMigration
|
723
838
|
#
|
@@ -768,7 +883,7 @@ module ActiveRecord
|
|
768
883
|
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
|
769
884
|
# even when migrating down:
|
770
885
|
#
|
771
|
-
# class SplitNameMigration < ActiveRecord::Migration[7.
|
886
|
+
# class SplitNameMigration < ActiveRecord::Migration[7.1]
|
772
887
|
# def change
|
773
888
|
# add_column :users, :first_name, :string
|
774
889
|
# add_column :users, :last_name, :string
|
@@ -796,7 +911,7 @@ module ActiveRecord
|
|
796
911
|
# In the following example, the new column +published+ will be given
|
797
912
|
# the value +true+ for all existing records.
|
798
913
|
#
|
799
|
-
# class AddPublishedToPosts < ActiveRecord::Migration[7.
|
914
|
+
# class AddPublishedToPosts < ActiveRecord::Migration[7.1]
|
800
915
|
# def change
|
801
916
|
# add_column :posts, :published, :boolean, default: false
|
802
917
|
# up_only do
|
@@ -810,8 +925,9 @@ module ActiveRecord
|
|
810
925
|
|
811
926
|
# Runs the given migration classes.
|
812
927
|
# Last argument can specify options:
|
813
|
-
#
|
814
|
-
# -
|
928
|
+
#
|
929
|
+
# - +:direction+ - Default is +:up+.
|
930
|
+
# - +:revert+ - Default is +false+.
|
815
931
|
def run(*migration_classes)
|
816
932
|
opts = migration_classes.extract_options!
|
817
933
|
dir = opts[:direction] || :up
|
@@ -848,7 +964,7 @@ module ActiveRecord
|
|
848
964
|
end
|
849
965
|
|
850
966
|
time = nil
|
851
|
-
ActiveRecord::
|
967
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection.pool.with_connection do |conn|
|
852
968
|
time = Benchmark.measure do
|
853
969
|
exec_migration(conn, direction)
|
854
970
|
end
|
@@ -873,6 +989,7 @@ module ActiveRecord
|
|
873
989
|
end
|
874
990
|
ensure
|
875
991
|
@connection = nil
|
992
|
+
@execution_strategy = nil
|
876
993
|
end
|
877
994
|
|
878
995
|
def write(text = "")
|
@@ -911,13 +1028,11 @@ module ActiveRecord
|
|
911
1028
|
end
|
912
1029
|
|
913
1030
|
def connection
|
914
|
-
@connection || ActiveRecord::
|
1031
|
+
@connection || ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
915
1032
|
end
|
916
1033
|
|
917
1034
|
def method_missing(method, *arguments, &block)
|
918
|
-
|
919
|
-
|
920
|
-
say_with_time "#{method}(#{arg_list})" do
|
1035
|
+
say_with_time "#{method}(#{format_arguments(arguments)})" do
|
921
1036
|
unless connection.respond_to? :revert
|
922
1037
|
unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
|
923
1038
|
arguments[0] = proper_table_name(arguments.first, table_name_options)
|
@@ -927,22 +1042,23 @@ module ActiveRecord
|
|
927
1042
|
end
|
928
1043
|
end
|
929
1044
|
end
|
930
|
-
return super unless
|
931
|
-
|
1045
|
+
return super unless execution_strategy.respond_to?(method)
|
1046
|
+
execution_strategy.send(method, *arguments, &block)
|
932
1047
|
end
|
933
1048
|
end
|
934
1049
|
ruby2_keywords(:method_missing)
|
935
1050
|
|
936
1051
|
def copy(destination, sources, options = {})
|
937
1052
|
copied = []
|
938
|
-
schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
|
939
1053
|
|
940
1054
|
FileUtils.mkdir_p(destination) unless File.exist?(destination)
|
1055
|
+
schema_migration = SchemaMigration::NullSchemaMigration.new
|
1056
|
+
internal_metadata = InternalMetadata::NullInternalMetadata.new
|
941
1057
|
|
942
|
-
destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
|
1058
|
+
destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration, internal_metadata).migrations
|
943
1059
|
last = destination_migrations.last
|
944
1060
|
sources.each do |scope, path|
|
945
|
-
source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
|
1061
|
+
source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration, internal_metadata).migrations
|
946
1062
|
|
947
1063
|
source_migrations.each do |migration|
|
948
1064
|
source = File.binread(migration.filename)
|
@@ -1001,9 +1117,9 @@ module ActiveRecord
|
|
1001
1117
|
# Determines the version number of the next migration.
|
1002
1118
|
def next_migration_number(number)
|
1003
1119
|
if ActiveRecord.timestamped_migrations
|
1004
|
-
[Time.now.utc.strftime("%Y%m%d%H%M%S")
|
1120
|
+
[Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
|
1005
1121
|
else
|
1006
|
-
|
1122
|
+
"%.3d" % number.to_i
|
1007
1123
|
end
|
1008
1124
|
end
|
1009
1125
|
|
@@ -1025,6 +1141,22 @@ module ActiveRecord
|
|
1025
1141
|
end
|
1026
1142
|
end
|
1027
1143
|
|
1144
|
+
def format_arguments(arguments)
|
1145
|
+
arg_list = arguments[0...-1].map(&:inspect)
|
1146
|
+
last_arg = arguments.last
|
1147
|
+
if last_arg.is_a?(Hash)
|
1148
|
+
last_arg = last_arg.reject { |k, _v| internal_option?(k) }
|
1149
|
+
arg_list << last_arg.inspect unless last_arg.empty?
|
1150
|
+
else
|
1151
|
+
arg_list << last_arg.inspect
|
1152
|
+
end
|
1153
|
+
arg_list.join(", ")
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
def internal_option?(option_name)
|
1157
|
+
option_name.start_with?("_")
|
1158
|
+
end
|
1159
|
+
|
1028
1160
|
def command_recorder
|
1029
1161
|
CommandRecorder.new(connection)
|
1030
1162
|
end
|
@@ -1057,19 +1189,44 @@ module ActiveRecord
|
|
1057
1189
|
end
|
1058
1190
|
end
|
1059
1191
|
|
1192
|
+
# = \Migration \Context
|
1193
|
+
#
|
1060
1194
|
# MigrationContext sets the context in which a migration is run.
|
1061
1195
|
#
|
1062
1196
|
# A migration context requires the path to the migrations is set
|
1063
1197
|
# in the +migrations_paths+ parameter. Optionally a +schema_migration+
|
1064
|
-
# class can be provided.
|
1065
|
-
#
|
1066
|
-
#
|
1198
|
+
# class can be provided. Multiple database applications will instantiate
|
1199
|
+
# a +SchemaMigration+ object per database. From the Rake tasks, \Rails will
|
1200
|
+
# handle this for you.
|
1067
1201
|
class MigrationContext
|
1068
|
-
attr_reader :migrations_paths, :schema_migration
|
1202
|
+
attr_reader :migrations_paths, :schema_migration, :internal_metadata
|
1203
|
+
|
1204
|
+
def initialize(migrations_paths, schema_migration = nil, internal_metadata = nil)
|
1205
|
+
if schema_migration == SchemaMigration
|
1206
|
+
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
1207
|
+
SchemaMigration no longer inherits from ActiveRecord::Base. If you want
|
1208
|
+
to use the default connection, remove this argument. If you want to use a
|
1209
|
+
specific connection, instantiate MigrationContext with the connection's schema
|
1210
|
+
migration, for example `MigrationContext.new(path, Dog.connection.schema_migration)`.
|
1211
|
+
MSG
|
1212
|
+
|
1213
|
+
schema_migration = nil
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
if internal_metadata == InternalMetadata
|
1217
|
+
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
1218
|
+
SchemaMigration no longer inherits from ActiveRecord::Base. If you want
|
1219
|
+
to use the default connection, remove this argument. If you want to use a
|
1220
|
+
specific connection, instantiate MigrationContext with the connection's internal
|
1221
|
+
metadata, for example `MigrationContext.new(path, nil, Dog.connection.internal_metadata)`.
|
1222
|
+
MSG
|
1223
|
+
|
1224
|
+
internal_metadata = nil
|
1225
|
+
end
|
1069
1226
|
|
1070
|
-
def initialize(migrations_paths, schema_migration = SchemaMigration)
|
1071
1227
|
@migrations_paths = migrations_paths
|
1072
|
-
@schema_migration = schema_migration
|
1228
|
+
@schema_migration = schema_migration || SchemaMigration.new(connection)
|
1229
|
+
@internal_metadata = internal_metadata || InternalMetadata.new(connection)
|
1073
1230
|
end
|
1074
1231
|
|
1075
1232
|
# Runs the migrations in the +migrations_path+.
|
@@ -1113,7 +1270,7 @@ module ActiveRecord
|
|
1113
1270
|
migrations
|
1114
1271
|
end
|
1115
1272
|
|
1116
|
-
Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
|
1273
|
+
Migrator.new(:up, selected_migrations, schema_migration, internal_metadata, target_version).migrate
|
1117
1274
|
end
|
1118
1275
|
|
1119
1276
|
def down(target_version = nil, &block) # :nodoc:
|
@@ -1123,20 +1280,20 @@ module ActiveRecord
|
|
1123
1280
|
migrations
|
1124
1281
|
end
|
1125
1282
|
|
1126
|
-
Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
|
1283
|
+
Migrator.new(:down, selected_migrations, schema_migration, internal_metadata, target_version).migrate
|
1127
1284
|
end
|
1128
1285
|
|
1129
1286
|
def run(direction, target_version) # :nodoc:
|
1130
|
-
Migrator.new(direction, migrations, schema_migration, target_version).run
|
1287
|
+
Migrator.new(direction, migrations, schema_migration, internal_metadata, target_version).run
|
1131
1288
|
end
|
1132
1289
|
|
1133
1290
|
def open # :nodoc:
|
1134
|
-
Migrator.new(:up, migrations, schema_migration)
|
1291
|
+
Migrator.new(:up, migrations, schema_migration, internal_metadata)
|
1135
1292
|
end
|
1136
1293
|
|
1137
1294
|
def get_all_versions # :nodoc:
|
1138
1295
|
if schema_migration.table_exists?
|
1139
|
-
schema_migration.
|
1296
|
+
schema_migration.integer_versions
|
1140
1297
|
else
|
1141
1298
|
[]
|
1142
1299
|
end
|
@@ -1195,16 +1352,20 @@ module ActiveRecord
|
|
1195
1352
|
end
|
1196
1353
|
|
1197
1354
|
def last_stored_environment # :nodoc:
|
1198
|
-
return nil unless
|
1355
|
+
return nil unless connection.internal_metadata.enabled?
|
1199
1356
|
return nil if current_version == 0
|
1200
|
-
raise NoEnvironmentInSchemaError unless
|
1357
|
+
raise NoEnvironmentInSchemaError unless connection.internal_metadata.table_exists?
|
1201
1358
|
|
1202
|
-
environment =
|
1359
|
+
environment = connection.internal_metadata[:environment]
|
1203
1360
|
raise NoEnvironmentInSchemaError unless environment
|
1204
1361
|
environment
|
1205
1362
|
end
|
1206
1363
|
|
1207
1364
|
private
|
1365
|
+
def connection
|
1366
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1367
|
+
end
|
1368
|
+
|
1208
1369
|
def migration_files
|
1209
1370
|
paths = Array(migrations_paths)
|
1210
1371
|
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
@@ -1215,7 +1376,7 @@ module ActiveRecord
|
|
1215
1376
|
end
|
1216
1377
|
|
1217
1378
|
def move(direction, steps)
|
1218
|
-
migrator = Migrator.new(direction, migrations, schema_migration)
|
1379
|
+
migrator = Migrator.new(direction, migrations, schema_migration, internal_metadata)
|
1219
1380
|
|
1220
1381
|
if current_version != 0 && !migrator.current_migration
|
1221
1382
|
raise UnknownMigrationVersionError.new(current_version)
|
@@ -1240,23 +1401,28 @@ module ActiveRecord
|
|
1240
1401
|
|
1241
1402
|
# For cases where a table doesn't exist like loading from schema cache
|
1242
1403
|
def current_version
|
1243
|
-
|
1404
|
+
connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1405
|
+
schema_migration = SchemaMigration.new(connection)
|
1406
|
+
internal_metadata = InternalMetadata.new(connection)
|
1407
|
+
|
1408
|
+
MigrationContext.new(migrations_paths, schema_migration, internal_metadata).current_version
|
1244
1409
|
end
|
1245
1410
|
end
|
1246
1411
|
|
1247
1412
|
self.migrations_paths = ["db/migrate"]
|
1248
1413
|
|
1249
|
-
def initialize(direction, migrations, schema_migration, target_version = nil)
|
1414
|
+
def initialize(direction, migrations, schema_migration, internal_metadata, target_version = nil)
|
1250
1415
|
@direction = direction
|
1251
1416
|
@target_version = target_version
|
1252
1417
|
@migrated_versions = nil
|
1253
1418
|
@migrations = migrations
|
1254
1419
|
@schema_migration = schema_migration
|
1420
|
+
@internal_metadata = internal_metadata
|
1255
1421
|
|
1256
1422
|
validate(@migrations)
|
1257
1423
|
|
1258
1424
|
@schema_migration.create_table
|
1259
|
-
|
1425
|
+
@internal_metadata.create_table
|
1260
1426
|
end
|
1261
1427
|
|
1262
1428
|
def current_version
|
@@ -1309,18 +1475,21 @@ module ActiveRecord
|
|
1309
1475
|
end
|
1310
1476
|
|
1311
1477
|
def load_migrated
|
1312
|
-
@migrated_versions = Set.new(@schema_migration.
|
1478
|
+
@migrated_versions = Set.new(@schema_migration.integer_versions)
|
1313
1479
|
end
|
1314
1480
|
|
1315
1481
|
private
|
1482
|
+
def connection
|
1483
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1484
|
+
end
|
1485
|
+
|
1316
1486
|
# Used for running a specific migration.
|
1317
1487
|
def run_without_lock
|
1318
1488
|
migration = migrations.detect { |m| m.version == @target_version }
|
1319
1489
|
raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
|
1320
|
-
result = execute_migration_in_transaction(migration)
|
1321
1490
|
|
1322
1491
|
record_environment
|
1323
|
-
|
1492
|
+
execute_migration_in_transaction(migration)
|
1324
1493
|
end
|
1325
1494
|
|
1326
1495
|
# Used for running multiple migrations up to or down to a certain value.
|
@@ -1329,15 +1498,15 @@ module ActiveRecord
|
|
1329
1498
|
raise UnknownMigrationVersionError.new(@target_version)
|
1330
1499
|
end
|
1331
1500
|
|
1332
|
-
result = runnable.each(&method(:execute_migration_in_transaction))
|
1333
1501
|
record_environment
|
1334
|
-
|
1502
|
+
runnable.each(&method(:execute_migration_in_transaction))
|
1335
1503
|
end
|
1336
1504
|
|
1337
1505
|
# Stores the current environment in the database.
|
1338
1506
|
def record_environment
|
1339
1507
|
return if down?
|
1340
|
-
|
1508
|
+
|
1509
|
+
@internal_metadata[:environment] = connection.pool.db_config.env_name
|
1341
1510
|
end
|
1342
1511
|
|
1343
1512
|
def ran?(migration)
|
@@ -1389,10 +1558,10 @@ module ActiveRecord
|
|
1389
1558
|
def record_version_state_after_migrating(version)
|
1390
1559
|
if down?
|
1391
1560
|
migrated.delete(version)
|
1392
|
-
@schema_migration.
|
1561
|
+
@schema_migration.delete_version(version.to_s)
|
1393
1562
|
else
|
1394
1563
|
migrated << version
|
1395
|
-
@schema_migration.
|
1564
|
+
@schema_migration.create_version(version.to_s)
|
1396
1565
|
end
|
1397
1566
|
end
|
1398
1567
|
|
@@ -1407,50 +1576,38 @@ module ActiveRecord
|
|
1407
1576
|
# Wrap the migration in a transaction only if supported by the adapter.
|
1408
1577
|
def ddl_transaction(migration, &block)
|
1409
1578
|
if use_transaction?(migration)
|
1410
|
-
|
1579
|
+
connection.transaction(&block)
|
1411
1580
|
else
|
1412
1581
|
yield
|
1413
1582
|
end
|
1414
1583
|
end
|
1415
1584
|
|
1416
1585
|
def use_transaction?(migration)
|
1417
|
-
!migration.disable_ddl_transaction &&
|
1586
|
+
!migration.disable_ddl_transaction && connection.supports_ddl_transactions?
|
1418
1587
|
end
|
1419
1588
|
|
1420
1589
|
def use_advisory_lock?
|
1421
|
-
|
1590
|
+
connection.advisory_locks_enabled?
|
1422
1591
|
end
|
1423
1592
|
|
1424
1593
|
def with_advisory_lock
|
1425
1594
|
lock_id = generate_migrator_advisory_lock_id
|
1426
1595
|
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
yield
|
1432
|
-
ensure
|
1433
|
-
if got_lock && !connection.release_advisory_lock(lock_id)
|
1434
|
-
raise ConcurrentMigrationError.new(
|
1435
|
-
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
1436
|
-
)
|
1437
|
-
end
|
1438
|
-
end
|
1439
|
-
end
|
1440
|
-
|
1441
|
-
def with_advisory_lock_connection(&block)
|
1442
|
-
pool = ActiveRecord::ConnectionAdapters::ConnectionHandler.new.establish_connection(
|
1443
|
-
ActiveRecord::Base.connection_db_config
|
1444
|
-
)
|
1445
|
-
|
1446
|
-
pool.with_connection(&block)
|
1596
|
+
got_lock = connection.get_advisory_lock(lock_id)
|
1597
|
+
raise ConcurrentMigrationError unless got_lock
|
1598
|
+
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
1599
|
+
yield
|
1447
1600
|
ensure
|
1448
|
-
|
1601
|
+
if got_lock && !connection.release_advisory_lock(lock_id)
|
1602
|
+
raise ConcurrentMigrationError.new(
|
1603
|
+
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
1604
|
+
)
|
1605
|
+
end
|
1449
1606
|
end
|
1450
1607
|
|
1451
1608
|
MIGRATOR_SALT = 2053462845
|
1452
1609
|
def generate_migrator_advisory_lock_id
|
1453
|
-
db_name_hash = Zlib.crc32(
|
1610
|
+
db_name_hash = Zlib.crc32(connection.current_database)
|
1454
1611
|
MIGRATOR_SALT * db_name_hash
|
1455
1612
|
end
|
1456
1613
|
end
|