db2 on Rails
DB2でさくさく実現するRESTfulなDBアプリ(2)

Railsでレガシーデータを蘇えらせるテクニック

日本アイ・ビー・エム株式会社
Team Ruby
山根 英彦
2008/10/30

実践:レガシーデータベースとRailsアプリケーションの連携

 はじめに、例として使用するレガシー表を準備します。

サンプルデータ付きのデータベースを作成しておく

 DB2では、db2samplコマンドを使用することでサンプルデータの格納されたデータベースを作成することができます。

 DB2のコマンド・ウィンドウを開き、リスト1のコマンドによってサンプルデータベースを作成します。

 リスト1の-sql オプションはリレーショナルデータの格納されたサンプル表を、-xml オプションはXMLデータの格納されたサンプル表を作成します。ここでは、両方のオプションを使用します。

 db2sampl コマンドは、ログインしているユーザー名をスキーマ名としたサンプル表を作成します。ここではdb2adminというスキーマ名を使用します(db2adminというユーザーでWindowsにログオンしています)。

●リスト1 サンプル用のDB2データ作成
C:\Program Files\IBM\SQLLIB\BIN> db2sampl -sql -xml

Creating database "SAMPLE"... Connecting to database "SAMPLE"... Creating tables and data in schema "DB2ADMIN"... Creating tables with XML columns and XML data in schema "DB2ADMIN"...
'db2sampl' processing complete.
C:\Program Files\IBM\SQLLIB\BIN>

 これでsampleという名前のデータベースが作成されました。このデータベースに対してActiveScaffoldを構成しなおしてもいいのですが、今回は前回作成したdemoプロジェクトの接続先データベースをsampleに変更します。

プロジェクトの接続先データベースの変更

 demoディレクトリ下のconfig\database.ymlファイルをエディタで開き、developmentと記載されている部分のdatabase:をsampleとします。サンプル表のスキーマ名がusername:と異なる場合は、password:とともに変更します(サンプル2)。

●サンプル2 config\database.yml(抜粋)
development:
  adapter: ibm_db
  database: sample
  username: db2admin
  password: db2admin

レガシー表とのマッピング方法

 次に、作成したサンプル表をレガシー表と見立てて、その表をActiveScaffoldを使用して表示・更新していく具体的な方法を紹介します。

 前述のとおり、ActiveRecordで表にアクセスするためには、ID生成列(INTEGER型のユニークな値をDB2が生成する列)として定義された主キー列が必要となります。以下で前述の13の3つのケースについての対応方法の詳細を紹介します。

ケース1:レガシー表に主キー列に相当するINTEGER型やBIGINT型の列が存在する場合

 「id」という名前ではなくても、表の主キー列に相当するINTEGER型やBIGINT型の列がすでに存在するケースです。このケースは比較的多いと予想されます。

レガシー表の内容を確認

 ここでは先ほど作成したサンプル表であるpurchaseorder表を例に解説します。purchaseorder表はリスト2のような定義の表です。

●リスト2 purchaseorder表の定義(describe tableの出力より)
C:\Program Files\IBM\SQLLIB\BIN>db2 describe table purchaseorder

                       Data type                     Column
Column name            schema    Data type name      Length     Scale Nulls
---------------------- --------- ------------------- ---------- ----- ------
POID                   SYSIBM    BIGINT                       8     0 いいえ
STATUS                 SYSIBM    VARCHAR                     10     0 いいえ
CUSTID                 SYSIBM    BIGINT                       8     0 はい
ORDERDATE              SYSIBM    DATE                         4     0 はい
PORDER                 SYSIBM    XML                          0     0 はい
COMMENTS               SYSIBM    VARCHAR                   1000     0 はい

  6 レコードが選択されました。

C:\Program Files\IBM\SQLLIB\BIN>db2 select identity from syscat.columns 
where tabname='PURCHASEORDER' and colname='POID' and tabschema
='DB2ADMIN'
IDENTITY -------- N 1 レコードが選択されました。 C:\Program Files\IBM\SQLLIB\BIN>

 この表では、poid列がBIGINT型の主キー列となっています。しかしながら、poid列はID生成列ではありません。

主キー列をID生成列に変更する

 まずは、表の定義を変更してpoid列をID生成列に変更します。ID生成列を定義するに当たり、リスト3のSQLでpoid列の最大値を求めておきます。

●リスト3 表定義の変更
C:\Program Files\IBM\SQLLIB\BIN>db2 SELECT MAX(POID) FROM PURCHASEORDER

1 -------------------- 5006
1 レコードが選択されました。
C:\Program Files\IBM\SQLLIB\BIN>

 次に、リスト4のコマンドを実行して、purchaseorder表のpoid列をID生成列に変更します。ID生成列のスタート値はリスト3で求めた最大値以降にします。

●リスト4 poid列をID生成列に変更
C:\Program Files\IBM\SQLLIB\BIN>db2 ALTER TABLE PURCHASEORDER ALTER COLUMN POID SET GENERATED ALWAYS AS IDENTITY (START WITH 6000, INCREMENT BY 1, CACHE 20)
DB20000I SQL コマンドが正常に完了しました。

C:\Program Files\IBM\SQLLIB\BIN>

 これで、poid列はID生成列となりました。

 ただし、このままでは主キー列と表の名前がRailsの規約に一致しません。次に、主キー列と表の名前をRails規約に一致させる方法を見ていきます。

主キー列と表の名前をRails規約に一致させる2つの方法

 

 前述のように、ここまでの作業だけでは主キー列と表の名前がRailsの規約に一致しません。この表にActiveRecordからアクセスする方法として、A:DB2側からのアプローチと、B:ActiveRecord側からのアプローチの2つがあります。  

 
A DB2側からのアプローチ:ビューを使って列名、表名を変更する

 DB2側からのアプローチとしては、ビューを作成し、poid列を「id」という名前の列に見せることでアクセスする方法が考えられます。

 サンプル3のCREATE VIEW文を使用してビューを作成します。このDDLは後ほどモデル作成後のスクリプトに追加します。

 DB2ではビューに対して更新を行うことが可能なのでこの方法で問題はありませんが、DB2以外のRDBMSの場合、仕様によってはビューの更新ができない可能性があるため、注意が必要です。

●サンプル3 CREATE VIEWのDDL
CREATE VIEW PURCHASEORDERS AS SELECT POID AS ID,STATUS,CUSTID,
ORDERDATE,PORDER FROM PURCHASEORDER

 このビューでは、poidを「id」とする以外に、Railsの規約にのっとり、表名を「purchaseorders」と複数形にしています。また、不要な列を除くことも可能です。ここでは、comment列は不要として定義から除外しています。

 次に、このpurchaseordersビューのためのモデルとコントローラを作成します。前回と同様、scriptディレクトリのgenerateを使い、リスト5のようにして作成します。

●リスト5 purchaseordersビュー用のモデルとコントローラを作成
C:\demo>ruby script\generate model purchaseorder status:string custid:string orderdate:date porder:xml
 exists app/models/
  exists test/unit/
  exists test/fixtures/
  create app/models/purchaseorder.rb
  create test/unit/purchaseorder_test.rb
  create test/fixtures/purchaseorders.yml
  create db/migrate
  create db/migrate/005_create_purchaseorders.rb
  
  C:\demo>

 ここで、db\migrateの下に作成された表作成のスクリプト005_create_purchaseorders.rbをサンプル4のように編集しておきます。executeを使用することで、migrate時に任意のSQLを実行できます。

●サンプル4 db\migrate\005_create_purchaseorders.rb
class CreatePurchaseorders < ActiveRecord::Migration
  def self.up
    execute "CREATE VIEW PURCHASEORDERS AS SELECT POID AS ID,
               STATUS,CUSTID,ORDERDATE,PORDER FROM PURCHASEORDER"
  end

  def self.down
    execute "DROP VIEW PURCHASEORDERS"
  end
end
  

 次に、app\controllersディレクトリの下にpurchaseorders_controller.rbというファイルを作成し、サンプル5のように記述し保存します。

●サンプル5 app\controllers\purchaseorders_controller.rb
class PurchaseordersController < ApplicationController
  active_scaffold :purchaseorder
  layout "activescaffold"
  end

 これで完了です。rake db:migrateを実行してビューを作成したら、ruby script\serverでサーバを起動して確認しましょう(図1)。

●図1 purchaseorders表の内容が表示された
fig1

 この状態では、主キー列(purchaseorders表のpoid列)の値が表示されていません。

 前回行ったActiveScaffoldのカスタマイズと同様、コントローラの中でlabelを使用して主キー列を表示させることができます。また、主キー列はID生成列であるため、明示的な値の入力はできません。そこで、コントローラにconf.create.columns.excludeを追加することにより「Create」のメニューからは除外します。

 app\controllersの下にあるpurchaseorders_controller.rbをサンプル6のように編集します。

●サンプル6 app\controllers\purchaseorders_controller.rb
class PurchaseordersController < ApplicationController
  active_scaffold :purchaseorder do |conf|
    conf.columns = [:id, :custid, :orderdate, :porder, :status]
    columns[:id].label = "ID"
    conf.create.columns.exclude :id
  end
  layout "activescaffold"
  end

 変更を保存後、Webブラウザをリロードすると図2のように表示されます。

●図2 poid列が表示された

 

B:ActiveRecord側からのアプローチ:表名と主キー列名の指定を変更する

 モデルクラスに既存表の表名と主キー列名を指定することによりアクセスします。purchaseorders表の例では、app\modelsディレクトリの下のpurchaseorder.rbファイルをサンプル7のように編集します。

●サンプル7 app\models\purchaseorder.rb
class Purchaseorder < ActiveRecord::Base
  set_table_name :purchaseorder
  set_primary_key :poid
end

 この方法では、既存表にダイレクトにアクセスするため、migrateによってデータベースオブジェクトの作成・削除を行いません。従って、db\migrateの下にある表作成のスクリプトは必要ありません。

 次ページではケース2、3の場合の対処法を見ていきます。

前のページへ 2/4 次のページへ

Index
DB2でさくさく実現するRESTfulなDBアプリ(2)
Railsでレガシーデータを蘇えらせるテクニック
・既存の表にActiveRecordを使うには?
・ActiveRecordを使ったマッピング
ActiveRecordが備える機能|ActiveRecordで表を作成する|DB2での主キーの扱い
→ Page 2
ケース1:
レガシー表に主キー列に相当するINTEGER型やBIGINT型の列が存在する場合
レガシー表の内容を確認|主キー列をID生成列に変更する|主キー列と表の名前をRails規約に一致させる2つの方法
ケース2:
レガシー表に主キー列に相当する列が存在するがMALLINT型の場合
ケース3:
レガシー表に主キー列に相当する列が存在しない、もしくは存在してもCHAR型やVARCHAR型の場合
コラム:読み込み専用の表としてアクセスさせたい場合
・レガシー表へのRESTfulなアクセス
・まとめ

DB2でさくさく実現するRESTfulなDBアプリ



Database Expert フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Database Expert 記事ランキング

本日月間