DB Migration in Rails 3

Rails 3.1로 업그레이드되면서, 마이그레이션 작업에 약간의 추가 메소드가 생겼습니다.


$ rails g model post title:string body:text

와 같이 명령을 수행할 때 만들어지는 마이그레이션 루비 파일의 내용을 보면 이전 up/down 메소드 대신 change 메소드 하나만 보이게 됩니다. 개발자로 하여금 코딩 시간을 줄일 수 있고 좀 더 지능적인 프레임워크로 진화하고 있는 느낌이 듭니다.

# in Rails 2.x
class CreatePosts < ActiveRecord::Migration
   def self.up
      create_table :posts do |t|
         t.string :title
         t.text :body
         t.timestamps

      end
   end

   def self.down
      drop_table :posts
   end

end

# in Rails 3.1
class CreatePosts < ActiveRecord::Migration

   def change
      create_table :posts do |t|
         t.string :title
         t.text :body
         t.timestamps
      end
   end

end

마이그레이션을 위해 실질적인 테이블을 물리적으로 만들기 위해서는 다음의 명령이 실행되어야 합니다


$ rake db:migration

와 같이 실행하면 아직 마이크레이션 되지 않은 마이그레이션 루비 파일들을 불러들여 실행하게 됩니다. 이러한 마이그레이션 루비파일들은 파일명 앞에 타임스탬프가 찍혀 있는데, 이렇게 마이그레이션 파일이 rake되면 해당 파일의 파일명 앞에 있는 타임스탬프가 schema_migrations 라는 테이블에 추가됩니다. 그래서 마이그레이션 rake 명령이 실행될 때 이 테이블을 검색해서 테이블에 파일의 타임스탬프가 있으면 수행을 하지 않게 됩니다.


$ rake db:migration:status

위의 명령을 수행하면 지금까지 수행되었던 마이그레이션 이력을 일견에 볼 수 있어 어디까지 마이그레이션 작업이 수행되었는지도 쉽게 알 수 있습니다.

자, 이렇게 마이그레이션을 위한 rake 작업을 한 후에 테이블을 수정할 상황이 발생할 경우, rake 작업을 취소하고 데이터베이스내 태이블을 롤백해야 하는데, 이 과정은 다음과 같습니다.


$ rake db:rollback

마이그레이션 작업이 취소되고 테이블이 롤백됩니다.

이후에 마이그레이션을 위한 루비 파일을 수정하고 다시 위에서 언급한 바와 같이 마이그레이션 rake 작업을 수행하면 됩니다.

때로는 특정 마이그레이션 파일을 롤백하고 싶은 경우가 있는데, 다음과 같이 VERSION= 다음에 해당 파일명 앞의 타임스탬프 숫자만을 추가해 주면 됩니다.

$ rake db:migrate:down VERSION=20080906120000

Rails 3.1의 change 메소드는 이러한 롤백과정에서 자동으로 반대기능을 하는 메소드를 추정해서 실행하게 됩니다.


$ rake db:migrate (in /home/rohit/code/migrahedron)

== CreatePosts: migrating ===========================
-- create_table(:posts)
-> 0.0012s

== CreatePosts: migrated (0.0013s) =====================

$ rake db:rollback (in /home/rohit/code/migrahedron)

== CreatePosts: reverting("posts")
-> 0.0007s

== CreatePosts: reverted (0.0008s)======================

그러나 자동으로 역방향 메소드를 실행하지 못하고 에러가 발생하는 경우가 있습니다.


class RemoveTitleFromPost < ActiveRecord::Migration
   def change
      remove_column :posts, :title
   end
end

$ rake db:rollback이런 경우에는 역방향 메소드 add_column이 호출될 때 정보가 부족하여, 즉, 데이터형에 대한 정보가 없기 때문에 에러가 발행하게 되는 것입니다.


== RemoveTitleFromPost: reverting =========================
rake aborted!

An error has occurred, this and all later migrations canceled:
ActiveRecord::IrreversibleMigration
(See full trace by running task with --trace)

이럴 경우에는 이전 버젼에서와 같이 up 또는 down 인스턴스 메소드를 구현해서 마이그레이션 루비 스크립트를 작성해 주어야 합니다.


class RemoveTitleFromPost < ActiveRecord::Migration
   def up
      remove_column :posts, :title
   end
   def down
      add_column :posts,:title,:string
   end
end

주의: self.up / self.down 클래스 메소드가 아니고 up / down 인스턴스 메소드로 작성해 주어야 합니다.