プロトタイピングに効くRoRのDB移行・変換機能Rubyでアジャイルプロトタイピング(4)

本記事はRuby on Rails(以下RoR)を使ってプロトタイプを作成し、アジャイルかつ正確にクライアントからの機能要件を取りまとめることを提案する連載「Rubyでアジャイルプロトタイピング」の第4回目です。これまでの連載では、アジャイルプロトタイピングについての解説、そしてプロトタイピングにおいてRubyやRoRがPDS(Plan/Do/See)サイクルの中でどのような効能をもたらすかについて解説を行ってきました。

» 2006年03月08日 12時00分 公開
[鍜治舍浩(永和システムマネジメント), 西川仁(永和システムマネジメン), 林秀一(アークピア),@IT]

 今回はRoRでアジャイルプロトタイピングの実践編として、筆者が特に気に入っているデータベースのマイグレーション機能を紹介したいと思います。データベースのマイグレーションはプロトタイピングのみならず、それ以降のフェーズでも活用できる非常に有用な機能であると考えています。

マイグレーションとは何か?

 そもそもマイグレーションとは何でしょうか? マイグレーション、特にデータベースにおけるマイグレーションとは、新しい環境に移行する際、整合性を保持したまま移行を行うためのツールであるといえるかと思います。


RoRにおけるマイグレーション

  RoRにおけるマイグレーション機能はActiveRecord::Migrationとそれを利用するフロントエンドに当たるRakeによって実現されています。

 RakeはRuby Make、つまり、Ruby版makeとでもいえるビルドツールですが、記述言語としてRubyを使用しているため、makeとはまったく異なる性質を持つものです。Rakeについての解説は今回の趣旨からは外れるため紹介は割愛させていただきますが、より詳しくRakeについてお知りになりたい方は、下記URLなどを参照ください。

ActiveRecord::Migration

 ActiveRecord::Migrationによって以下のスキーマ操作を行うことができます。

  • テーブルの作成・削除
  • カラムの追加・削除・変更
  • インデックスの追加・削除

 上記のような簡単なスキーマ変更をこのマイグレーション機能により行うことが可能ですが、ActiveRecordの現在のバージョン1.13.2では外部キーの操作などの複雑なテーブルの設定は、SQLを直接記述する必要があります。しかし、今後RoRがバージョンアップを重ね洗練されていくに従い、マイグレーション時にSQLをいちいち記述しなければならない機会はどんどん必要なくなっていくでしょう。頻繁なバージョンアップに伴う機能の充実と使い勝手の向上(本当に目覚ましいものがあります)もRoRの1つの魅力です。

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

 ActiveRecord::Migration は以下のデータベースに対応しています。

  • MySQL
  • PostgreSQL
  • Oracle
  • SQLite

 DB2の対応は含まれていませんが、プロトタイプを作成する場合においては、ターゲットのデータベースを使用する必要はないため、特に問題にはならないでしょう。今回の解説では軽量データベースとして高い人気があるSQLite(バージョン3.2.8、以下SQLite 3)を使用します。

まずはテーブルの作成

 Migration機能を使用してテーブルを作成してみましょう。簡単な例として、次のようなテーブルを考えます。

テーブル名:members
属性名 id データ型 長さ 必須
メンバ ID id integer  
名前 name varchar 255  

 このテーブルを生成するための Migration のサブクラスをgenerateスクリプトにより作成します。

≪$ script/generate migration create_members≫
            create db/migrate
            create db/migrate/001_create_members.rb

スクリプトを実行すると db/migrate以下に 001_create_members.rb というファイルが生成されます。このファイルの先頭の数字 001 がバージョン番号(バージョン1)になります。

 001_create_members.rb をエディタなどで開き、CreateMembersクラスの up メソッドにテーブル生成のための記述を追加します。

class CreateMembers < ActiveRecord::Migration
    def self.up
        ≪create_table :members do |t|≫
            ≪t.column :id, :integer≫
            ≪t.column :name, :string≫
        ≪end≫
    end
    def self.down
    end
end

 テーブルが生成されたかどうか、データベースに接続し確認してみます(ここでは、開発用データベースをdevelopment.sqlite3という名前で作成しました)。

≪$ sqlite3 db/development.sqlite3≫
SQLite version 3.2.8
Enter ".help" for instructions
sqlite> .schema
CREATE TABLE members ("id" INTEGER PRIMARY KEY NOT NULL, "name"
varchar(255));
CREATE TABLE schema_info (version integer);

 schema_infoというテーブルが追加されていますが、これは、Migrationがバージョン管理を行うためのもので、中身は現在のバージョン番号が格納されています。

スキーマのアップグレード

 次に、SQLite 3で作成したmembersテーブルに住所を格納するためのカラムaddressを追加してみましょう。バージョン1のmembersテーブルは以下のような定義でした。

≪$ sqlite3 db/development.sqlite3≫
SQLite version 3.2.8
Enter ".help" for instructions
sqlite> .schema members
CREATE TABLE members (
id integer primary key,
name varchar(255)
);

 generateスクリプトでaddressカラム追加用のMigrationのサブクラスを作成します。

≪$ script/generate migration add_address_members≫
create db/migrate
create db/migrate/002_add_address_members.rb

 addressカラムの追加をメソッドupに記述します。

class AddAddressMembers < ActiveRecord::Migration
    def self.up
        ≪add_column :members, :address, :text # address カラムを追加≫
    end
     def self.down
    end
end

 rakeでMigrationを実行します。

≪$ rake migrate≫

 addressカラムが追加されたことを確認します。

≪$ sqlite3 db/development.sqlite3≫
Enter ".help" for instructions
sqlite> .schema
CREATE TABLE members ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255), "address" text);
CREATE TABLE schema_info (version integer);

スキーマのダウングレード

 スキーマのダウングレードは、Migrationのサブクラスのdownメソッドに変更内容を記述します。スキーマのアップグレードで適用したバージョン2のスキーマをダウングレードするには、以下のようにバージョン2のdownメソッドを定義します。

≪$ sqlite3 db/development.sqlite3≫
Enter ".help" for instructions
sqlite> .schema
CREATE TABLE members ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255), "address" text);
CREATE TABLE schema_info (version integer);

 rakeでMigrationを実行します。

≪$ rake migrate VERSION=1≫

 ダウングレードする場合は、バージョンを明記します。上記の例では、バージョン2から1つダウングレードするため、1を指定します。バージョンを明記する場合は、現在のバージョンから指定したバージョンへのアップ/ダウングレードになります。また、バージョンを明記しない場合は、最新のバージョンへのアップグレードになります。

 address カラムが削除されたことを確認します。

≪$ sqlite3 db/development.sqlite3≫
SQLite version 3.2.8
Enter ".help" for instructions
sqlite> .schema
CREATE TABLE members ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255));
CREATE TABLE schema_info (version integer);

 このようにアップグレードで追加したカラムをダウングレード時には削除しておくといったように、対称的に定義しておくことによって、スキーマの変更管理が容易になります。


 プロトタイプを作成していると、さまざまなアイデアを試してみたくなることでしょう。また、思い付いたアイデアは、モデルの設計から変更を加える必要があることもしばしばあるかと思います。そして、実際にあるアイデアを試してみたが、やはりうまくいかないので、モデルを元に戻したい−−ActiveRecord::Migrationによってスキーマの変更管理がカンタンに行えるようになったため、プロトタイピング本来の目的であるさまざまなアイデアを試行錯誤することが可能になるのです。ActiveRecord::Migrationがアジャイルプロトタイピングを支える柱の1つであるといっても過言ではないでしょう。

 次回は、RoR実践編の続きです。アジャイルプロトタイピングの成果物をどのように扱うのか? についてお伝えしたいと思います。

Copyright © ITmedia, Inc. All Rights Reserved.

注目のテーマ