Nice programing

실패한 Rails 마이그레이션 롤백

nicepro 2020. 10. 7. 08:16
반응형

실패한 Rails 마이그레이션 롤백


실패한 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.0932 초
-add_column (: asset, : error)
레이크 중단!
오류가 발생하여 이후의 모든 마이그레이션이 취소되었습니다.

잘못된 인수 개수 (3 개에 2 개)

좋아, 롤백하자.

$ rake db : rollback
== AddLevelsToRoles : 되돌리기 ============================================ ==
-remove_column (: roles, : level)
   -> 0.0778 초
== AddLevelsToRoles : 되돌림 (0.0779s) =====================================

응? 그것은 실패한 마이그레이션이 아니라 SimpleTest 이전의 마지막 마이그레이션이었습니다. (그리고 마이그레이션 출력에 버전 번호가 포함되어 있으면 좋을 것입니다.)

따라서 실패한 마이그레이션 SimpleTest에 대해 아래로 실행 해 보겠습니다.

$ rake db : migrate : down VERSION = 20090326173033
$

아무 일도 일어나지 않으며 출력도 없습니다. 하지만 어쨌든 마이그레이션을 실행했을까요? 따라서 SimpleTest 마이그레이션에서 구문 오류를 수정하고 다시 실행 해 보겠습니다.

$ rake db : migrate : up VERSION = 20090326173033
== SimpleTest : 마이그레이션 ============================================ ========
-add_column (: assets, : test, : integer)
레이크 중단!
Mysql :: Error : 중복 열 이름 'test': ALTER TABLE ʻassets` ADD`test` int (11)

아니. 분명히 migrate : down이 작동하지 않았습니다. 실패하지 않고 실행되지 않습니다.

데이터베이스에 수동으로 들어가 제거하고 테스트를 실행하는 것 외에는 중복 테이블을 제거 할 방법이 없습니다. 그것보다 더 나은 방법이 있어야합니다.


불행히도 MySQL에 대해 실패한 마이그레이션을 수동으로 정리해야합니다. MySQL은 트랜잭션 데이터베이스 정의 변경을 지원하지 않습니다.

Rails 2.2에는 PostgreSQL 용 트랜잭션 마이그레이션이 포함되어 있습니다. Rails 2.3에는 SQLite에 대한 트랜잭션 마이그레이션이 포함되어 있습니다.

이것은 지금 당장 문제에 도움이되지는 않지만 향후 프로젝트에서 데이터베이스를 선택할 수있는 경우 마이그레이션이 훨씬 더 즐겁기 때문에 트랜잭션 DDL을 지원하는 데이터베이스를 사용하는 것이 좋습니다.

업데이트-이것은 Alejandro Babio가 여기에 또 다른 답변으로보고 한 Rails 4.2.7 및 MySQL 5.7에서 2017 년에도 여전히 사실입니다.


지정된 버전으로 이동하려면 다음을 사용하십시오.

rake db:migrate VERSION=(the version you want to go to)

그러나 마이그레이션이 부분적으로 실패하면 먼저 정리해야합니다. 한 가지 방법은 다음과 같습니다.

  • down마이그레이션 방법을 편집하여 up작업 한 부분 만 실행 취소하십시오.
  • 이전 상태 (시작 위치)로 다시 마이그레이션
  • 마이그레이션 수정 (에 대한 변경 사항 실행 취소 포함 down)
  • 다시 시도하십시오

좋아요, 여러분, 여기에 실제로하는 방법이 있습니다. 위의 답변이 무엇에 대해 말하는지 모르겠습니다.

  1. 상향 마이그레이션의 어느 부분이 효과가 있는지 파악하십시오. 주석 처리하십시오.
  2. 또한 중단 된 마이그레이션 부분을 주석 처리 / 제거하십시오.
  3. 마이그레이션을 다시 실행하십시오. 이제 이미 완료된 부분을 건너 뛰고 마이그레이션의 손상되지 않은 부분을 완료합니다.
  4. Uncomment the bits of the migration you commented out in step 1.

You can migrate down and back up again if you want to verify that you've got it right now.


I agree that you should use PostgreSQL when possible. However, when you are stuck with MySQL, you can avoid most of these problems by trying your migration on your test database first:

rake db:migrate RAILS_ENV=test

You can revert to the previous state and try again with

rake db:schema:load RAILS_ENV=test

At 2015 with Rails 4.2.1 and MySQL 5.7, a failed migration can't be fixed with standard rake actions that Rails provide, as it was at 2009.

MySql does not support rollback of DDL statments (at MySQL 5.7 Manual). And Rails can not do anything with that.

Also, we can check how Rails is doing the job: A migration is wrapped in a transaction depending on how connection adapter respond to :supports_ddl_transactions?. After a search of this action at rails source (v 4.2.1), I found that only Sqlite3 and PostgreSql supports transactions, and by default it is not supported.

Edit Thus the current answer to the original question: A failed MySQL migration must be manually fixed.


The easy way to do this is to wrap all of your actions in a transaction:

class WhateverMigration < ActiveRecord::Migration

 def self.up
    ActiveRecord::Base.transaction do
...
    end
  end

  def self.down
    ActiveRecord::Base.transaction do
...
    end
  end

end

As Luke Francl noted, "MySql['s MyISAM tables don't] support transactions" -- which is why you might consider avoiding MySQL in general or at least MyISAM in particular.

If you're using MySQL's InnoDB, then the above will work just fine. Any errors in either up or down will back out.

BE AWARE some types of actions cannot be reverted via transactions. Generally, table changes (dropping a table, removing or adding columns, etc.) cannot be rolled back.


Run just the down migration from the console:

http://gilesbowkett.blogspot.com/2007/07/how-to-use-migrations-from-console.html (click through to his pastie)


I had a typo (in "add_column"):

def self.up

add_column :medias, :title, :text
add_colunm :medias, :enctype, :text

end

def self.down

remove_column :medias, :title
remove_column :medias, :enctype   

end

and then your problem (cannot undo partly failed migration). after some failed googling i ran this:

def self.up

remove_column :medias, :title
add_column :medias, :title, :text
add_column :medias, :enctype, :text

end

def self.down

remove_column :medias, :title
remove_column :medias, :enctype

end

as you can see i just added the correction line by hand, and then removed it again, before i checked it in.


Alejandro Babio's answer above provides the best current answer.

One additional detail I want to add:

When the myfailedmigration migration fails, it is not considered as applied, and this can be verified by running rake db:migrate:status, which would show output similar to the following:

$  rake db:migrate:status
database: sample_app_dev

 Status   Migration ID    Migration Name
--------------------------------------------------
   up      20130206203115  Create users
   ...
   ...
   down    20150501173156  Test migration

The residual effect of add_column :assets, :test, :integer being executed on the failed migration will have to be reversed at the database level with a alter table assets drop column test; query.

참고URL : https://stackoverflow.com/questions/686852/rolling-back-a-failed-rails-migration

반응형