diff options
author | Marc-Andre Lafortune <github@marc-andre.ca> | 2012-08-06 22:25:01 -0400 |
---|---|---|
committer | Marc-Andre Lafortune <github@marc-andre.ca> | 2012-12-21 13:54:51 -0500 |
commit | 65e154f33b54acf40b51082fc5b681ba605015d9 (patch) | |
tree | 2db947cc5aea5cc1815a1e13122a23ed68271e78 | |
parent | 24653c945ad3fdce4cb5890a9cc7565753decda0 (diff) | |
download | rails-65e154f33b54acf40b51082fc5b681ba605015d9.tar.gz rails-65e154f33b54acf40b51082fc5b681ba605015d9.tar.bz2 rails-65e154f33b54acf40b51082fc5b681ba605015d9.zip |
Allow revert of whole migration [#8267]
-rw-r--r-- | activerecord/lib/active_record/migration.rb | 42 | ||||
-rw-r--r-- | activerecord/test/cases/invertible_migration_test.rb | 63 |
2 files changed, 102 insertions, 3 deletions
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 14c1fb9ae2..c605c2da7f 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -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: + # + # require_relative '2012121212_tenderlove_migration' + # + # class FixupTLMigration < ActiveRecord::Migration + # def change + # revert TenderloveMigration + # + # create_table(:apples) do |t| + # t.string :variety + # end + # end + # end # - def revert + # 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) diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index 6d285e23d7..6b81e600af 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -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" |