Allow revert of whole migration [#8267]

This commit is contained in:
Marc-Andre Lafortune 2012-08-06 22:25:01 -04:00
parent 24653c945a
commit 65e154f33b
2 changed files with 102 additions and 3 deletions

@ -379,7 +379,8 @@ def initialize(name = self.class.name, version = nil)
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 @@ def initialize(name = self.class.name, version = nil)
# 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 @@ def revert
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 @@ def self.down
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 @@ def test_migrate_revert
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"