FrontPage  Index  Search  Changes  Login

MigrationによるDB管理

Migrationとは

Migration とは、Railsで使うデータベースの管理機能で、テーブル作成・カラ ムの追加/変更などの作業を一元管理できます。SQL でスキーマを書くのでは なく、Rails独自の記法(Rubyの文法の範囲内)を使ってDB管理を行います。以 下のようなメリットがあります。

  • スキーマのバージョン管理ができる
  • rake コマンドでスキーマのバージョンアップ/ロールバックが可能
  • データベースに依存しない書き方ができるので、他のデータベースに切り替えるのが容易

対応しているデータベース

現在、対応しているデータベースは MySQL, PostgreSQL, SQLite, SQL Server, Oracle です。

今後、対応DBは増えていくと思います。最新情報は、

http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

の Database support のところを見てください。

また、ActiveRecord の各アダプタに migration に対応しているかの真偽を返 すメソッドがあります。

ActiveRecord::Base.connection.supports_migrations?

これが true なら migration 機能が使えます。

使い方

スキーマの各バージョン毎に Migration 定義ファイルを作成します。定義ファ イルは ActiveRecord::Migration を継承したクラスをひとつ含みます。この クラスに up と down というクラスメソッドを定義することにより、スキーマ のアップグレード/ダウングレードを行います。

generate migration

まず、最初のテーブル作成用の定義ファイルをつくってみます。以下のように して script/generate で migration 定義ファイルを新規に生成します。

% ruby script/generate migration InitialSchema

InitialSchemaの部分は任意の名前を指定でき、この部分が Migration 定義ファ イル内のクラス名になります(名前は initial_schema の形でも可)。定義ファ イルは以下のような内容で、db/migrate/001_initial_schema.rb のような名 前で生成されます。

class InitialSchema < ActiveRecord::Migration
  def self.up
  end

  def self.down
  end
end

定義ファイルの編集

上記のファイルを編集し、アップグレード/ダウングレード時の処理を記述します。

self.up は、アップグレード時の処理です。ここでは、最初のテーブル作成時 の定義ファイルなので、主にスキーマ定義を行うことになります。たとえは以 下の記述が可能です。

create_table(テーブル名, オプション)
テーブルを作成する。ブロックの中でカラム定義ができる。
drop_table(テーブル名)
テーブルを削除する。
rename_table(テーブル名, 新テーブル名)
テーブル名を変更する。
add_column(テーブル名, カラム名, 型, オプション)
テーブルにカラムを追加する。
remove_column(テーブル名, カラム名)
カラムを削除する。
rename_column(テーブル名, カラム名, 新カラム名)
カラム名を変更する。
add_index(テーブル名, カラム名)
インデックスを追加する。

詳細は以下を参照してください。

http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html

では、例としてRailsでWikiクローンを作るのDBスキーマ定義をMigrationの機能で実現してみ ます。定義ファイルは以下のようになります。

class InitialSchema < ActiveRecord::Migration
  def self.up
    create_table(:pages) {|t|
      t.column :name, :string, :null => false
      t.column :title, :string
      t.column :freezeflag, :boolean
      t.column :updated_at, :datetime
      t.column :content, :text
    }
    add_index :pages, :name

    create_table(:confs) {|t|
      t.column :site_name, :string, :null => false
      t.column :author_name, :string
      t.column :theme, :string
      t.column :use_wikiname, :boolean
      t.column :use_plugin, :boolean
    }
    Conf.create :site_name => 'hoge hoge', :author_name => '名無しさん',
      :theme => 'hiki', :use_wikiname => true, :use_plugin => false

    create_table(:users) {|t|
      t.column :name, :string, :limit => 10
      t.column :crypted_password, :string, :limit => 14
    }
    User.create :name => 'admin', :password => 'admin'
  end

  def self.down
    drop_table :pages
    drop_table :confs
    drop_table :users
  end
end

create_table でテーブル定義をします。引数でテーブル名とオプションを指 定できます(上記例ではオプションを指定していません。ほとんどの場合は不 要でしょう)。例では ActiveRecord にはつきものの id カラムがありません が、特に指定しない限り自動で付加されます。

create_table のブロック内でカラム定義を行います。

t.column :name, :string, :null => false

は、SQL で書くと

name varchar(255) NOT NULL

というような意味になります。この抽象表現で使用できる型と、実際に SQL でどのように変換されるかは、各DBアダプタの native_database_types で定 義されています。例えば sqlite ならば、activerecord の lib/active_record/connection_adapters/sqlite_adapter.rb というファイ ルの中にあります。

     def native_database_types #:nodoc:
       {
         :primary_key => "INTEGER PRIMARY KEY NOT NULL",
         :string      => { :name => "varchar", :limit => 255 },
         :text        => { :name => "text" },
         :integer     => { :name => "integer" },
         :float       => { :name => "float" },
         :datetime    => { :name => "datetime" },
         :timestamp   => { :name => "datetime" },
         :time        => { :name => "datetime" },
         :date        => { :name => "date" },
         :binary      => { :name => "blob" },
         :boolean     => { :name => "boolean" }
       }
     end

その他、テーブル定義で使用できる命令についての詳細は、以下をみてください。

http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html

テーブル定義以外にも、普通に ActiveRecord を使うときのように

    User.create :name => 'admin', :password => 'admin'

と書いて、テーブル内にデータを挿入することもできます。

注意 ここでの ActiveRecord の操作は rails の app/models/*.rb ファイルの内容 に従います。上記の User の例では、テーブル定義に password というカラム はありませんが、モデル(app/models/users.rb)のほうで定義している (RailsでWikiクローンを作る10参照)のでこのような書き方が可能です。

self.down メソッド内では、ダウングレードするときの処理内容を定義します。 up と down を対で書いておくことにより、スキーマ定義を任意のバージョン に戻せるようになります。例では、テーブルを削除する drop_table を記述し ています。

database.yml の設定

config/database.yml を適切に設定します。migration は database.yml で指定 したデータベースに適用されます。

Migration実行

migrationを実行するには、RAILS_ROOT で以下のコマンドを実行します。

rake migrate

development 環境の現在のデータベースに対して、適用されていないすべての 定義ファイルが番号順に適用されます。どの番号まで適用されているかを覚え ておくためにDB内にschema_infoというテーブルが自動でつくられます。

また、定義を戻したい場合は

rake migrate VERSION=X

と番号を指定すればその番号まで戻ります。

rake migrate VERSION=0

とすると、一番最初の状態に戻ることになります。

また、デフォルトでは migrate は development 環境のデータベースに対して 実行されますが production 環境でやりたい場合は

rake RAILS_ENV=production migrate

のように実行します。

既存のDBからmigration定義ファイルを作るには

migrationという便利な機能があることを知らずに、すでに SQL で create table してDBスキーマを定義してしまった、という人に朗報です。

rails 環境では、以下のようにすると現在のデータベースの情報を読み込んで migration で使える形式のスキーマ定義ファイルを生成してくれます。

rake db_schema_dump

とすると db/schema.rb というファイルができあがります。たとえば RailsでWikiクローンを作る のデータベースがすでにある状態で、rake db_schema_dump する と以下の内容の db/schema.rb ファイルが生成されます。

# This file is autogenerated. Instead of editing this file, please use the
# migrations feature of ActiveRecord to incrementally modify your database, and
# then regenerate this schema definition.

ActiveRecord::Schema.define(:version => 1) do

  create_table "confs", :force => true do |t|
    t.column "site_name", :string, :null => false
    t.column "author_name", :string
    t.column "theme", :string
    t.column "use_wikiname", :boolean
    t.column "use_plugin", :boolean
  end

  create_table "pages", :force => true do |t|
    t.column "name", :string, :null => false
    t.column "title", :string
    t.column "freezeflag", :boolean
    t.column "updated_at", :datetime
    t.column "content", :text
  end

  add_index "pages", ["name"], :name => "pages_name_index"

  create_table "users", :force => true do |t|
    t.column "name", :string, :limit => 10
    t.column "crypted_password", :string, :limit => 14
  end

end

これの create_table や add_index の部分を抜き取ってこれば migration 定 義ファイルは簡単に作成できるでしょう。前述の、手で作った定義ファイルと 若干表記は異なりますが、意味はだいたい同じです。ただし、以下の2点に注意。

  • create_table に :force => true というオプションが指定されているため、 rake migrate すると既存のテーブルは drop される。
  • 既存のテーブルの中身はコピーされない。初期値を insert したいなら手で追加する。
  • self.down メソッドは手で書く

schema dump 機能を使えば、既存の DB も migration を使うやり方に移行し やすいと思います。

Last modified:2006/02/08 14:04:01
Keyword(s):
References:[FrontPage]