1. ホーム
  2. mysql

[解決済み] 失敗したRailsのマイグレーションをロールバックする

2023-06-11 16:15:41

質問

失敗した rails のマイグレーションをロールバックするにはどうしたらよいでしょうか。私が期待するのは rake db:rollback を実行すれば、失敗したマイグレーションを元に戻せると思うのですが、そうではなく、前のマイグレーション(失敗したマイグレーションから1つ引いたもの)をロールバックしています。そして rake db:migrate:down VERSION=myfailedmigration もうまくいきません。私は何度かこれに遭遇しましたが、非常にいらいらさせられます。以下は、この問題を再現するために私が行った簡単なテストです。

class SimpleTest < ActiveRecord::Migration
  def self.up
    add_column :assets, :test, :integer
    # the following syntax error will cause the migration to fail
    add_column :asset, :test2, :integer
  end

  def self.down
    remove_column :assets, :test
    remove_column :assets, :test2
  end
end

の結果です。

== SimpleTest: 移行中 ==================================================================================================================================
-- add_column(:assets, :test, :integer)
   -> 0.0932s
-- add_column(:asset, :error)
rake aborted!
エラーが発生しました。以降の移行はすべてキャンセルされます。

引数の数が間違っている (2 for 3)

OK、ロールバックしましょう。

$ rake db:rollback
== AddLevelsToRoles: 元に戻す ================================================================================================================================
-- remove_column(:roles, :level)
   -> 0.0778s
== AddLevelsToRoles: reverted (0.0779s) ============================================================================================================

これはSimpleTestの前の最後のマイグレーションで、失敗したマイグレーションではありません。(そして、ああ、マイグレーション出力にバージョン番号が含まれているといいのですが)。

では、失敗したマイグレーションのSimpleTestを実行してみましょう。

$ rake db:migrate:down VERSION=20090326173033
$

何も起こらないし、出力もされない。でも、もしかしたらマイグレーションが実行されたのかも?そこで、SimpleTestマイグレーションの構文エラーを修正し、もう一度実行してみましょう。

$ rake db:migrate:up VERSION=20090326173033
== SimpleTest: migration ======================================================================================================================= SimpleTest: migration
-- add_column(:assets, :test, :integer)
rake aborted!
Mysql::Error: カラム名 'test' が重複しています。ALTER TABLE `assets` ADD `test` int(11)

だめです。明らかにmigrate:downがうまくいかなかった。失敗しているわけではなく、実行されていないだけです。

手動でデータベースに行って削除してからテストを実行する以外に、その重複したテーブルを取り除く方法はありません。それよりも良い方法があるはずです。

どのように解決するのですか?

残念ながら、MySQL については、失敗した移行を手動でクリーンアップする必要があります。MySQL は、トランザクションによるデータベース定義の変更をサポートしていません。

Rails 2.2には、PostgreSQLのトランザクション移行が含まれています。Rails 2.3では、SQLite用のトランザクションマイグレーションが含まれています。

これは今すぐの問題には役立ちませんが、もし将来のプロジェクトでデータベースを選択できるのであれば、トランザクションDDLをサポートするものを使うことをお勧めします。

更新 - これは2017年のRails 4.2.7とMySQL 5.7でも同じで、Alejandro Babioがこちらの別の回答で報告しています。