mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Allow revert of whole migration [#8267]
This commit is contained in:
parent
24653c945a
commit
65e154f33b
2 changed files with 102 additions and 3 deletions
|
@ -379,7 +379,8 @@ module ActiveRecord
|
|||
self.verbose = true
|
||||
self.delegate = new
|
||||
|
||||
# Reverses the migration commands for the given block.
|
||||
# Reverses the migration commands for the given block and
|
||||
# the given migrations.
|
||||
#
|
||||
# The following migration will remove the table 'horses'
|
||||
# and create the table 'apples' on the way up, and the reverse
|
||||
|
@ -399,9 +400,25 @@ module ActiveRecord
|
|||
# end
|
||||
# end
|
||||
#
|
||||
# This command can be nested.
|
||||
# Or equivalently, if +TenderloveMigration+ is defined as in the
|
||||
# documentation for Migration:
|
||||
#
|
||||
def revert
|
||||
# require_relative '2012121212_tenderlove_migration'
|
||||
#
|
||||
# class FixupTLMigration < ActiveRecord::Migration
|
||||
# def change
|
||||
# revert TenderloveMigration
|
||||
#
|
||||
# create_table(:apples) do |t|
|
||||
# t.string :variety
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# This command can be nested.
|
||||
def revert(*migration_classes)
|
||||
run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
|
||||
if block_given?
|
||||
if @connection.respond_to? :revert
|
||||
@connection.revert { yield }
|
||||
else
|
||||
|
@ -415,12 +432,31 @@ module ActiveRecord
|
|||
send(cmd, *args, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def reverting?
|
||||
@connection.respond_to?(:reverting) && @connection.reverting
|
||||
end
|
||||
|
||||
# Runs the given migration classes.
|
||||
# Last argument can specify options:
|
||||
# - :direction (default is :up)
|
||||
# - :revert (default is false)
|
||||
def run(*migration_classes)
|
||||
opts = migration_classes.extract_options!
|
||||
dir = opts[:direction] || :up
|
||||
dir = (dir == :down ? :up : :down) if opts[:revert]
|
||||
if reverting?
|
||||
# If in revert and going :up, say, we want to execute :down without reverting, so
|
||||
revert { run(*migration_classes, direction: dir, revert: true) }
|
||||
else
|
||||
migration_classes.each do |migration_class|
|
||||
migration_class.new.exec_migration(@connection, dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def up
|
||||
self.class.delegate = self
|
||||
return unless self.class.respond_to?(:up)
|
||||
|
|
|
@ -51,6 +51,23 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
class RevertWholeMigration < SilentMigration
|
||||
def initialize(name = self.class.name, version = nil, migration)
|
||||
@migration = migration
|
||||
super(name, version)
|
||||
end
|
||||
|
||||
def change
|
||||
revert @migration
|
||||
end
|
||||
end
|
||||
|
||||
class NestedRevertWholeMigration < RevertWholeMigration
|
||||
def change
|
||||
revert { super }
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
if ActiveRecord::Base.connection.table_exists?("horses")
|
||||
ActiveRecord::Base.connection.drop_table("horses")
|
||||
|
@ -90,6 +107,52 @@ module ActiveRecord
|
|||
assert !migration.connection.table_exists?("horses")
|
||||
end
|
||||
|
||||
def test_migrate_revert_whole_migration
|
||||
migration = InvertibleMigration.new
|
||||
[LegacyMigration, InvertibleMigration].each do |klass|
|
||||
revert = RevertWholeMigration.new(klass)
|
||||
migration.migrate :up
|
||||
revert.migrate :up
|
||||
assert !migration.connection.table_exists?("horses")
|
||||
revert.migrate :down
|
||||
assert migration.connection.table_exists?("horses")
|
||||
migration.migrate :down
|
||||
assert !migration.connection.table_exists?("horses")
|
||||
end
|
||||
end
|
||||
|
||||
def test_migrate_nested_revert_whole_migration
|
||||
revert = NestedRevertWholeMigration.new(InvertibleRevertMigration)
|
||||
revert.migrate :down
|
||||
assert revert.connection.table_exists?("horses")
|
||||
revert.migrate :up
|
||||
assert !revert.connection.table_exists?("horses")
|
||||
end
|
||||
|
||||
def test_revert_order
|
||||
block = Proc.new{|t| t.string :name }
|
||||
recorder = ActiveRecord::Migration::CommandRecorder.new(ActiveRecord::Base.connection)
|
||||
recorder.instance_eval do
|
||||
create_table("apples", &block)
|
||||
revert do
|
||||
create_table("bananas", &block)
|
||||
revert do
|
||||
create_table("clementines")
|
||||
create_table("dates")
|
||||
end
|
||||
create_table("elderberries")
|
||||
end
|
||||
revert do
|
||||
create_table("figs")
|
||||
create_table("grapes")
|
||||
end
|
||||
end
|
||||
assert_equal [[:create_table, ["apples"], block], [:drop_table, ["elderberries"]],
|
||||
[:create_table, ["clementines"], nil], [:create_table, ["dates"], nil],
|
||||
[:drop_table, ["bananas"]], [:drop_table, ["grapes"]],
|
||||
[:drop_table, ["figs"]]], recorder.commands
|
||||
end
|
||||
|
||||
def test_legacy_up
|
||||
LegacyMigration.migrate :up
|
||||
assert ActiveRecord::Base.connection.table_exists?("horses"), "horses should exist"
|
||||
|
|
Loading…
Reference in a new issue