중간 migration을 한 번 더 실행시키는 방법

8372 단어 migrationRails

환경



Amazon Linux
# rake about
sinatra                   1.4.7
ruby                      2.3.1p112 
Environment               staging
Database adapter          mysql2
Database schema version   201610xxxxxxxxx

배경



스테이징 환경은 여러 멤버가 만나고 있습니다. 어느새, migration는 이렇게 느꼈다.
# RACK_ENV=staging bundle exec rake db:migrate:status
database: xxx_staging

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20160826080803  Create xxx
   up     20160929044948  Create xxx
   up     20160929045000  Create xxx
   up     20160929045041  Create xxx
   up     20161111073930  A(add column is_prime)
   up     20161116033102  B
   up     20161116105100  C

확실히 전부 migration 전부 실행되고 있는 것처럼 보입니다만, 확인해 보면, [A]는 실행되고 있지 않는 것 같습니다. 다음 오류가 발생했습니다.
 ActiveModel::UnknownAttributeError - unknown attribute 'is_prime' for table_a

즉시 db/structure.sql 파일을 확인한 후 table_a에 is_prime이 없었습니다. 즉, 중간 migration(A)가 실행되지 않음

대책



다시 시도



물론 DB를 지우고 모든 migration을 다시 시작하는 것은 가장 빠르지만 데이터를 내보내고 가져오지 않으면 안 되고 조금 번거롭고 나중에 발생할 가능성이 낮습니다만, 만약 프로덕션 그런 일이 일어나면 어떻게 대응해야할까.
mysqldump -uroot db_name > dump.sql
RACK_ENV=staging bundle exec rake db:drop && RACK_ENV=staging bundle exec rake db:create && RACK_ENV=staging bundle exec rake db:migrate  
mysql -uroot db_name < dump.sql

다른 방법



그 migration만 실행시켜 보았다


RACK_ENV=staging bundle exec rake db:migrate:redo VERSION=20161111073930

그러면 다음 오류가 발생했습니다.
Mysql2::Error: Can't drop 'is_prime'; check that column/key exist:

즉, redo는 [down & up]이라는 구현이 되어 있습니다.

롤백했다.


RACK_ENV=staging bundle exec rake db:rollback STEP=4

↑와 같은 에러가 나왔다.
Mysql2::Error: Can't drop 'is_prime'; check that column/key exist:

한 걸음씩 하면 [A]까지는 할 수 있어 이런 느낌이 듭니다.
# RACK_ENV=staging bundle exec rake db:migrate:status
database: xxx_staging

 Status   Migration ID    Migration Name
--------------------------------------------------
   up       20160826080803  Create xxx
   up       20160929044948  Create xxx
   up       20160929045000  Create xxx
   up       20160929045041  Create xxx
   up       20161111073930  A(add column is_prime)
   down     20161116033102  B
   down     20161116105100  C

글쎄, 맞아! 원래 지금 is_prime는 존재하지 않기 때문입니다.

migration 파일을 제거해 보았습니다.



migration은 db/migration아래의 파일을 차례로 실행할 것이다. 하지만 두 번 롤백하고 20161111073930_xx_xx.rb를 제거하고 migration을 실행하고 그 후 20161111073930_xx_xx.rb를 되돌려 실행하면 잘 할 수 없다고 생각했지만 아무것도 변하지 않았다.

하지만 db/migration의 한 migration 파일을 실행했는지 여부라는 기록이 분명 다른 곳에 있다는 것을 알았다. 파일명만으로 결정하는 것이 아니다.

migration 테이블 수정


mysql> use auction_staging;
Database changed
mysql> show tables;
+---------------------------+
| Tables_in_auction_staging |
+---------------------------+
| ar_internal_metadata      |
| xxx_results               |
| xxx                       |
| schema_migrations         |
|        ....               |
+---------------------------+
11 rows in set (0.00 sec)

mysql> select * from schema_migrations;
+----------------+
| version        |
+----------------+
| 20160826080803 |
| 20160929044948 |
| 20160929045000 |
| 20160929045041 |
| 20161111073930 |
| 20161116033102 |
| 20161116105100 |
+----------------+
12 rows in set (0.00 sec)

과연, 20161111073930이라는 row를 지울 수 있는, 반드시 롤백을 할 수 있을 것!
select * from schema_migrations where version = '20161111073930';
delete   from schema_migrations where version = '20161111073930';

두 번 롤백하고 migration하면 고쳤습니다!
RACK_ENV=staging bundle exec rake db:rollback STEP=2
RACK_ENV=staging bundle exec rake db:migration

마지막



@jhoshina 다양한 조언 해 주셔서 감사합니다! 살아났습니다!

좋은 웹페이지 즐겨찾기