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


82

실패한 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이 작동하지 않았습니다. 실패하지 않고 실행되지 않습니다.

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

답변:


79

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

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

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

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


1
훌륭 해요, 감사합니다. 나는 PGSQL로 새로운 프로젝트를 할 것이므로 그것이 옵션이라는 것을 아는 것이 좋습니다.
insane.dreamer

이것은 여전히 ​​최선의 답변이므로 현상금 imho가 가치가 있습니다.
nathanvda

20

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

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

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

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

감사. 예, 마이그레이션이 실패 할 때까지 다시 마이그레이션 할 수 있다는 것을 알고 있지만 마이그레이션 기록이 긴 경우 때때로 문제가 될 수 있습니다. 이상적으로 그들은 모두 잘 실행되어야하지만, 더 자주 나는 그것들이
부분적으로

20

좋습니다. 여러분이 실제로하는 방법은 다음과 같습니다. 위의 답변이 무엇에 대해 말하는지 모르겠습니다.

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

지금 가지고 있는지 확인하려면 아래로 마이그레이션했다가 다시 백업 할 수 있습니다.


2
매우 유사한 작업을 수행하지만 2 단계를 "중단 된 마이그레이션 부분 수정"으로 바꿉니다.
Don Kirkby

2
마지막 요점을 강조 할 가치가 있습니다 bundle exec rake db:migrate:redo. 한 단계 뒤로 이동하고 한 단계 앞으로 이동하므로 최신 마이그레이션이 끝까지 실행되는지 확인할 수 있습니다. 이는 일부 코드 업데이트와 함께 마이그레이션을 푸시해야 할 때마다 좋은 방법입니다.
mahemoff

12

가능하면 PostgreSQL을 사용해야한다는 데 동의합니다. 그러나 MySQL을 사용하는 경우 먼저 테스트 데이터베이스에서 마이그레이션을 시도하여 이러한 문제의 대부분을 피할 수 있습니다.

rake db:migrate RAILS_ENV=test

이전 상태로 돌아가서 다시 시도 할 수 있습니다.

rake db:schema:load RAILS_ENV=test

대답보다는 해결 방법이 더 많지만 이것은 이전에 나에게 발생하지 않은 좋은 아이디어입니다.
Emily

10

2015 년 Rails 4.2.1 및 MySQL 5.7에서 실패한 마이그레이션은 2009 년과 마찬가지로 Rails가 제공하는 표준 레이크 작업으로 수정할 수 없습니다.

MySql은 DDL 구문의 롤백을 지원하지 않습니다 ( MySQL 5.7 Manual에서 ). 그리고 Rails는 그것으로 아무것도 할 수 없습니다.

또한 Rails가 작업을 수행하는 방법을 확인할 수 있습니다 . 연결 어댑터가 .NET에 응답하는 방식에 따라 마이그레이션이 트랜잭션으로 래핑 됩니다 :supports_ddl_transactions?. Rails 소스 (v 4.2.1)에서이 작업을 검색 한 후 Sqlite3PostgreSql 만 트랜잭션을 지원하며 기본적으로 지원되지 않음을 발견했습니다.

편집 따라서 원래 질문에 대한 현재 답변 : 실패한 MySQL 마이그레이션은 수동으로 수정해야합니다.


나는이 대답을 잘 이해하지 못합니다. 버전 번호를 업데이트하는 것 외에는 원래 수락 된 대답에 아무것도 추가하지 않습니다.
nathanvda

1
원래 질문에 대해 매우 사실입니다. 앤드류 그림 (Andrew Grimm)에 대한 현상금 시작 : "2009 년 3 월 질문이 제기 된 이후 상황이 바뀌 었는지 알고 싶습니다." 현재 답변이며 향후 변경 사항을 확인할 수있는 방법을 제공합니다.
Alejandro Babio

8

이를 수행하는 쉬운 방법은 트랜잭션에서 모든 작업을 래핑하는 것입니다.

class WhateverMigration < ActiveRecord::Migration

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

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

end

Luke Francl이 언급했듯이 "MySql [의 MyISAM 테이블은 트랜잭션을 지원하지 않습니다]"-이것이 MySQL을 일반적으로 피하거나 적어도 특히 MyISAM을 피하는 이유입니다.

MySQL의 InnoDB를 사용하는 경우 위의 내용이 잘 작동합니다. 위 또는 아래의 오류는 모두 취소됩니다.

조심하세요 행동의 일부 유형의 거래를 통해 되돌릴 수 없습니다. 일반적으로 테이블 변경 (테이블 삭제, 열 제거 또는 추가 등)은 롤백 할 수 없습니다.


5
MyISAM이나 InnoDB의 문제가 아닙니다. InnoDB는 트랜잭션을 지원하지만 트랜잭션 데이터베이스 정의 (DDL) 변경을 지원하지 않습니다. PostgreSQL에서는 테이블을 삭제 한 다음 해당 변경 사항을 롤백 할 수 있습니다!
Luke Francl 2009

1
Luke가 맞습니다. mysql은 DDL 변경 사항에 대한 트랜잭션을 지원하지 않습니다. 테이블에서 열을 추가하고 제거하는 것과 같은 정리를 스스로 고려해야합니다.
Leon Guan


1

오타 ( "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

종료

보시다시피 손으로 수정 선을 추가 한 다음 체크인하기 전에 다시 제거했습니다.


1

위의 Alejandro Babio의 답변은 가장 좋은 현재 답변을 제공합니다.

추가하고 싶은 추가 세부 사항 :

하면 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;쿼리 를 사용하여 데이터베이스 수준에서 되돌려 야 합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.