失敗した Rails 移行のロールバック
-
22-08-2019 - |
質問
失敗した 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: migrating ===================================================== -- add_column(:assets, :test, :integer) -> 0.0932s -- add_column(:asset, :error) rake aborted! An error has occurred, all later migrations canceled: wrong number of arguments (2 for 3)
OK、ロールバックしましょう:
$ rake db:rollback == AddLevelsToRoles: reverting =============================================== -- remove_column(:roles, :level) -> 0.0778s == AddLevelsToRoles: reverted (0.0779s) ======================================
はぁ?これは、失敗した移行ではなく、SimpleTest の前の最後の移行でした。(そして、移行の出力にバージョン番号が含まれていれば良いのですが。)
そこで、失敗した移行の SimpleTest に対して down を実行してみましょう。
$ rake db:migrate:down VERSION=20090326173033 $
何も起こらず、出力もありません。しかし、とにかく移行を実行したのでしょうか?そこで、SimpleTest 移行の構文エラーを修正し、再度実行してみます。
$ rake db:migrate:up VERSION=20090326173033 == SimpleTest: migrating ===================================================== -- add_column(:assets, :test, :integer) rake aborted! Mysql::Error: Duplicate column name 'test': ALTER TABLE `assets` ADD `test` int(11)
いいえ。明らかに、mitigate:down は機能しませんでした。失敗しているのではなく、実行していないだけなのです。
手動でデータベースにアクセスして削除し、テストを実行する以外に重複テーブルを削除する方法はありません。それよりも良い方法があるはずです。
解決
残念なことに、手動でMySQLの失敗の移行をクリーンアップする必要があります。 MySQLはトランザクションデータベースの定義の変更をサポートしていません。
レール2.2は、PostgreSQLのトランザクションの移行を含みます。レール2.3はSQLiteのためにトランザクションの移行が含まれます。
これは本当に今、あなたの問題のためのお手伝いをしませんが、あなたは将来のプロジェクトのデータベースの選択肢を持っている場合、それははるかに快適な移行を作るので、私はトランザクションのDDLをサポートするものを使用することをお勧めします。
のアップデート - これは、ここで別の答えにアレハンドロBabioによって報告Railsの4.2.7とMySQL 5.7、に、2017年にはまだ本当です。の
。他のヒント
指定したバージョンに移動するには、次のコマンドを使用します。
rake db:migrate VERSION=(the version you want to go to)
ただし、移行が途中で失敗した場合は、最初に移行をクリーンアップする必要があります。1 つの方法は次のとおりです。
- 編集する
down
の一部を元に戻すだけの移行方法up
それはうまくいきました - 以前の状態 (開始した場所) に戻る
- 移行を修正します (変更を元に戻すなど)
down
) - もう一度やり直してください
OK、皆さん、これが実際のやり方です。上記の回答が何を言っているのかわかりません。
- 上への移行のどの部分が機能したかを確認します。それらをコメントアウトしてください。
- また、壊れた移行の部分をコメントアウトするか削除します。
- 移行を再度実行します。これで、すでに完了した部分をスキップして、移行の壊れていない部分が完了します。
- 手順 1 でコメントアウトした移行の部分のコメントを解除します。
すぐに取得したことを確認したい場合は、下に移行して再度バックアップすることができます。
私は、可能な場合、あなたは、PostgreSQLを使用する必要があることに同意するものとします。あなたがMySQLので立ち往生しているときしかし、あなたが最初のテストデータベースに移行を試みることによって、これらの問題のほとんどを回避することができます:
rake db:migrate RAILS_ENV=test
あなたが以前の状態に戻して再び試すことができます。
rake db:schema:load RAILS_ENV=test
Rails 4.2.1 と MySQL 5.7 を使用する 2015 年では、2009 年と同様に、失敗した移行は Rails が提供する標準の rake アクションでは修正できません。
MySql は DDL ステートメントのロールバックをサポートしていません ( MySQL 5.7 マニュアル)。そして、Rails はそれに対して何もできません。
また、Rails がどのようにジョブを実行しているかを確認することもできます。移行というのは、 トランザクションにラップされる 接続アダプターの応答方法に応じて :supports_ddl_transactions?
. 。Rails ソース (v 4.2.1) でこのアクションを検索したところ、次のことがわかりました。 スクライト3 そして PostgreSql トランザクションをサポートし、 デフォルト それはサポートされていません。
編集したがって、元の質問に対する現在の答えは次のようになります。失敗した MySQL 移行は手動で修正する必要があります。
これを行う簡単な方法は、トランザクションにあなたの行動のすべてをラップすることです。
class WhateverMigration < ActiveRecord::Migration
def self.up
ActiveRecord::Base.transaction do
...
end
end
def self.down
ActiveRecord::Base.transaction do
...
end
end
end
ルークFranclは、「MySQLのサポート取引[ 'sのMyISAMテーブルにはない]」、述べたように - 。あなたは一般的または具体的には、少なくともMyISAMテーブルにMySQLを回避検討するかもしれない理由です。
あなたはMySQLのInnoDBのを使用している場合は、上記だけで正常に動作します。上または下のいずれかにエラーがあると、バックアウトされます。
に注意して行動のいくつかのタイプは、トランザクションを経由して元に戻すことはできません。一般的に、(など、列を削除または追加して、テーブルをドロップ)テーブルの変更がロールバックすることができない。
コンソールからちょうどダウンの移行を実行します:
のhttp://gilesbowkett.blogspot .COM / 2007/07 /どのように使用-移行-から-console.html に(彼pastieにクリックスルー)
私はタイプミスがあった( "ADD_COLUMN" で):
DEFするself.up
add_column :medias, :title, :text add_colunm :medias, :enctype, :text
終了
DEFするself.down
remove_column :medias, :title remove_column :medias, :enctype
終了
と、あなたの問題(一部の移行の失敗を元に戻すことはできません)。いくつかのグーグルで失敗した後、私はこれを実行しました。
あなたが見ることができるようにDEFするself.up
remove_column :medias, :title add_column :medias, :title, :text add_column :medias, :enctype, :text
終了
DEFするself.down
remove_column :medias, :title remove_column :medias, :enctype
終了
私はそれを確認する前に、ちょうど手で補正ラインを追加し、再度それを取り除いています。
上記のアレハンドロBabioの答えは最高の現在の答えを提供します。
私は追加したい1つの追加の詳細ます:
myfailedmigration
マイグレーションが失敗した場合、、それが適用されるように考慮されていない、これは次のような出力を示すであろう、rake db:migrate:status
を実行することによって確認することができます:
$ rake db:migrate:status
database: sample_app_dev
Status Migration ID Migration Name
--------------------------------------------------
up 20130206203115 Create users
...
...
down 20150501173156 Test migration
失敗したマイグレーション上で実行されるadd_column :assets, :test, :integer
の残留効果はalter table assets drop column test;
クエリを使用してデータベースレベルで反転されなければならない。