2003年10月16日号

「システムはオブジェクト指向 Ruby & Flash」(#006)   
                                                          福井修@Fsys

【○】本日のお題  サーバサイドで Ruby&PostgreSQL 連携 ━━━━━━━━━
 
10月もあっという間に半ばです。秋の天気は変わりやすいですね。

前回注1)より【 実践編 】ということで まず MVCモデル を Ruby&ActionScript
で実装する というテーマで「Flashコンポーネントを利用した方法で Flashを 
View に採用する方式は、リッチクライアント実現へとても有利です。」と書き
ました。本日は、サーバサイドのRuby-DB連携 Model実装がテーマです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ 新しいMVCモデルは、Viewを Flash ActionScript で実装
────────────────────────────────────
 まず前回の復習を少し。Javaでの今後のWeb開発はJSF(JavaServer Faces)注2)
が主流になってゆくと思われます。これすなわち それ以前の現在のやり方の賞
味期限は切れてゆくことになる訳です。

これは、新しいタームをいつもいつも追い続け走り続けなければならないという
毎度のパターンですね。

このJSFのキーワードは、「簡単に」です。

すなわち現在は「複雑である」ことをJava陣営はよく認識していることの反映な
のでしょう。複雑さを隠蔽し、見かけ上は、簡単にという考え方は.NETにも採用
されています。.NETのC#/VBもひとつの選択肢です。

しかしながらそれらの方式でより「簡単に」実装できるようになったとしても、
HTMLだけでのクライアントの表現には、限界があり、ここに根本的な弱点があり
ます。

具体例をひとつ挙げます。「 Webで折れ線グラフを描きそれをマウスで操作しよ
うとするとどう実装しますか?」

JSFや.NETだけでは、所詮不可能です。実現するには、Eolas裁判でテーマとなっ
たところのプラグインなどを利用するしかありません。

また尖った人たち(先回りして何でも解ってくれる)だけを相手にするのであれ
ば操作性は2の次でかまわないのですが、そうではない多数を対象とするには、
ユーザビリティを追求しなければなりません。ユーザビリティを追求しようとす
るとどうしてもリッチクライアントの道を避けて通れません。

そうなるとリッチクライアントに正面から取り組み、かつMVCモデルの利点(ユー
ザインターフェースが変わっても業務ロジックは独立して扱える)を享受するに
は、ViewにFlashを採用するのが、有利そうです。
Flashでは、様々なコンポーネントが存在しており 注3)、そのコンポーネントが
サポートしている範囲は、簡単に実装できるので、時間を節約できます。
また本来のアニメなどの表現力は、実に強力です。
まあ Flashは世界的にメジャーでしょうから、その成果は、おいしく頂くのが得
策でしょう。

 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ オブジェクト指向を志向するなら Model を Ruby で実装
────────────────────────────────────
ViewをFlash ActionScript でというのは、有力なひとつの解です。
では、Control や Model は何を使って実装するのが得策なのでしょう?

Controlは Viewとのやりとりが多いので、いろいろな選択肢はあります。
前回もControlは、ActionScriptの場合と、サーバサイドの場合があることを書
きました。

Modelは、今回のテーマとなりますが、DBとのやりとりがメインとなりますの
で、DBとのインターフェースが簡単で優れているものが良い訳です。

Javaでは、ModelはJSPでは実装しないでJavaBeans,EJB(Enterprize Java Beans)
で実装となります。PHPは、DBとのインターフェースが、良くこなれているので、
その面でModel用にも使われますが、もともとHTML文書に埋め込むところのView
向けが原点ですから、土俵が違います。

JSPはViewを記述するのに用いられ、Modelを記述するにはJSPよりJavaを用いる
のはその方が適材適所だからです。「 HTML文書を基本にプログラムを埋め込む
方式(タグベースの言語)」の JSPPHP、ColdFusionMarkupLanguage(CFML)
をサーバサイドの Model実装に採用するのは、やれば出来ますが、適材適所では
ありません。ここは重要なポイントです!。

Modelをオブジェクト指向で実装するのであれば、もともとオブジェクト指向で
はない言語( Perlなど)より、オブジェクト指向言語C++,Java,C#など)を採
用するのが正解です。そして、さらなる省コストを実現するには、オブジェクト
指向スクリプト言語PythonRubyが有利です。

結局日本発のオープンソーススクリプト言語 Ruby がBESTな選択となります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ RubyでDBをアクセスする Ruby&PostgreSQL 連携 実装例
────────────────────────────────────
 今回はModel部分にスポットを当てます。Model/Control/View連携は【応用編】
でやります。
9回目に【 応用編 】Ruby&Flash&PostgreSQL での 郵便番号検索を予定してい
ますので、今回は、そのサーバサイドの準備も兼ねます。

1.環境整備
 1.1 Linux 環境準備
     ルート権限のあるマシンを準備します。
     私は、Vineを愛用しています。( Vine2.6r1 )

 1.2 PostgreSQLインストール
     DBは、オープンソースで定評のあるPostgreSQLを使います。
     PostgreSQLはいろいろ進化を遂げ、富士通も援軍に回っています。注4)
     PostgreSQLのインストールは、他のサイトなど注5)を参考にして下さい。
     
     2003/10/15現在の最新は、postgresql-7.3.4.tar.gz です。
     ftp://ftp.jaist.ac.jp/dbms/PostgreSQL/source/v7.3.4/
     などから入手します。

 1.3 Rubyインストール
     Ruby は、8月に 1.8.0が公開されましたので、最新を使います。
     既に rpm などで、旧版が入っているなら $ rpm -e ruby などで
     旧版は、削除します。
     
    (1) ログインして自分のホームへ(/home/hogeとします)
       $ pwd
       /home/hoge
       
    (2) w3m にてサイトに入りダウンロード場所まで移動し ダウンロード
       $ w3m http://www.ruby-lang.org/ja/20020102.html
       注)w3mktermから使えるテキストブラウザです。

       Netscape,MojiraなどでももちろんOK

    (3) /usr/local/srcでソースを展開。
       $ cd /usr/local/src
       $ sudo tar fxzv /home/hoge/ruby-1.8.0.tar.gz

       リンク作成 ( バージョンの切り替えが簡単なように )
       $ sudo ln -s  ruby-1.8.0 ruby
       $ cd ruby

    (4) configure スクリプトを実行。
       $ sudo ./configure 

    (5) コンパイル。
       $ sudo make

    (6) インストール。
       $ sudo make install

    (7) 共有ライブラリがインストールされるので、ldconfig を実行。
       $ sudo /sbin/ldconfig

    (8) 動作確認 バージョンを問い合わせ
       $ ruby -v
       ruby 1.8.0 (2003-08-04) [i686-linux]
       
        が応答されたらOKです。
  
 1.4 Ruby-PostgreSQLインストール

    RubyからPostgreSQLにアクセスするには、Ruby-PostgreSQL拡張ライブラリ
    が必要です。先に、Ruby 及び PostgreSQL がインストールされている必要
    があります。
    (1) ログインして自分のホームへ(/home/hogeとします)
       $ pwd
       /home/hoge
       
    (2) 次のサイトに入りダウンロード
       http://www.postgresql.jp/interfaces/ruby/archive/ruby-postgres-0.7.1.tar.gz

    (3) /usr/local/srcでソースを展開。
       $ cd /usr/local/src
       $ sudo tar fxzv /home/hoge/ruby-postgres-0.7.1.tar.gz

       リンク作成 ( バージョンの切り替えが簡単なように )
       $ sudo ln -s  ruby-postgres-0.7.1 ruby
       $ cd ruby

    (4) extconf.rb を実行。★ここはポイントです。
        --with-pgsql-lib-dir と --with-pgsql-include-dir で
        PostgreSQL のライブラリ及びインクルードファイルがインストールさ
        れている場所を指定します。

      $ sudo ruby extconf.rb --with-pgsql-lib-dir=/usr/local/pgsql/lib \
                      --with-pgsql-include-dir=/usr/local/pgsql/include

    (5) コンパイル。★このLD_RUN_PATH設定もポイントです。
       $ sudo env LD_RUN_PATH=/usr/local/pgsql/lib make

    (6) インストール。
       $ sudo make install

2.DBデータ登録
   郵便番号のPostgreSQLへの登録は、以前に「ツボによく利くJAVA & DB」
    (#010)注6)で、とりあげましたので、そちらも参照してください。 

 2.1 郵便番号データダウンロード
   郵便番号サイトの場所が変わっています。注7)

 2.2 郵便番号データ変換編集
   解凍したファイルは、SHIFT_JISコードで、Linux上のPostgreSQLは、
   通常 EUCコードを用いるので、コード変換が必要となります。

   また インターネット上で扱うことも考慮すると半角カナも全角カナ
   に変換します。
   
   さらに PostgreSQL でテーブルに流しこんでやるのに便利な copy
   コマンドが使えるのですが、その場合 Defaultでは、区切り文字は
   ダブルクォーテーションとカンマでなくタブなのです。

   そこで、これらの変換を一気に掛けてやります。

    require "nkf"
    ARGF.each do | line |
      line.gsub(/"/,'')
      line.gsub(/,/,"\t")
      print NKF.nkf('-XSe', line)
    end

  上記スクリプトを 例えば s2e.rb として
   $ ruby ./s2e.rb KEN_ALL.CSV > ken_all.euc
  で実行して 変換後のファイルを作成します。

 2.3 DBテーブル定義、登録
 
  1) DB定義
     postgresユーザで post という名前のデータベースを作成します。
    $ createdb post
    
  2) DBテーブル定義
    次の crate table をします。
  -- ─────────────────────────────────
  create table postlist           -- ■ 郵便番号簿
  -- ─────────────────────────────────
  (
      jiscode         text,
      old_id          varchar(5),
      post_id         char(7),
      ken_k           text,
      si_k            text,
      tyou_k          text,
      ken             text,
      si              text,
      tyou            text,
      somezips        int4,
      aza             int4,
      choume          int4,
      sometowns       int4,
      changed         int4,
      changed_why     int4
  );
  create index newcodeindex on postlist using btree(post_id);
  grant select on postlist    to nobody;

  新郵便番号は、7桁固定なので、この項目は固定長にしてindexを張ります。

  crate tableする方法は、いろいろありますが、一例として上のテキストで
  postlist.sql というテキストファイルを作成し、postgresユーザで

    $ psql post < postlist.sql

  の様にファイルからコマンドを入力することもできます。
  
  3) DBテーブルデータ登録

   変換後のファイルken_all.eucを postlist テーブルに流し込むには、

    $ psql post

    これでSQLインタプリタを立ち上げて

    post=# \copy postlist from ken_all.euc

    と copyコマンドでテーブル名とテキストファイルを指定します。

    \.

    と表示されたら正常に登録完了です。

   DBの登録結果は、ODBC経由でAccessCSE 注8) などでも確認できます。

3.Ruby での PostgreSQLアクセス

 3.1 DBアクセスライブラリ
   PostgreSQLへのアクセスには、ミドルウェア層をライブラリ化します。
   これは「 Ruby活用編 〜 RubyPostgreSQL でメンバ制掲示板を作る 」
   http://fsys.net/lms/docs/lms20020526.txt
   の中のPostgreSQLアクセス wrapper class を利用します。
   pgCon.rb ファイルを require すると DBConnectionクラスを使用出来ます。

 3.2 郵便番号 検索要求に対し、検索結果を応答
   やっと 核心に入ります。今回は、Modelとして郵便番号 検索要求に対し、
   検索結果をログファイルに書き出す処理を Ruby で実装します。

#!/usr/local/bin/ruby -T -Ke
#-----------------------------------------------------------------------
=begin
=  selpostal.rb
郵便番号検索
=end
#-----------------------------------------------------------------------
# @version A00 2003/10/14 福井@Fsys 
# $Id: $
#-----------------------------------------------------------------------
# 実行場所get
BaseDir = File.dirname(File.expand_path(__FILE__)).untaint
# Pathのうち最後を除く
basePath = File.dirname(BaseDir)
# ライブラリ検索用PATH追加
$LOAD_PATH.unshift basePath + '/lib'

# 実行結果ログファイル 月日時でサイクリックに
fname = basePath + "/log/kintai" + Time.now.strftime("%m%d%H")+ ".log"     
log = open(fname,"a")       # ログファイルオープン

# ライブラリ読み込み
require 'cgi'
require 'pgCon'

# cgiデータget
cgi = CGI.new

zipno   = cgi['zipno'][0].to_s
ad1     = cgi['ad1'][0].to_s

# 初期化
results = nil
out     = nil

# DB接続
db = DBConnection.new
db.connect

# 郵便番号から検索
unless zipno.empty?
  zipno.to_i
  results = db.query("select post_id,ken,si,tyou from postlist where " \
                     " post_id ~ '#{zipno}' order by post_id ;")
# 市区町村から検索
else
  unless ad1.empty?
    results = db.query("select post_id,ken,si,tyou from postlist " \
                       " where si~ '#{ad1}' or tyou~ '#{ad1}' " \
                       " order by post_id ;")
  end
end
if results
  results.each{ |record|
    post_id,ken,si,tyou = record
    out = ''
    out << post_id[0,3]
    out << '-'
    out << post_id[3,4]
    out << ' '
    out << ken
    out << ' '
    out << si
    out << ' '
    out << tyou if tyou
    log.puts out 
  }
end 

ここから 入力受付用 htmlファイル

郵便番号検索


郵便番号
市区町村


ファイル書き出し、正規表現の処理、多重代入、イテレータなどいろいろな テクニックが、実装されていますので、参考にしてください。 次回は「【 実践編 】LoadVars連携での ログイン認証 」です。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ※ 注釈、資料、参考情報 ──────────────────────────────────── 注1) http://www.melma.com/mag/02/m00020302/a00000631.html 注2) JavaServer Facesを理解する(上)(下) http://www.atmarkit.co.jp/fjava/special/jsf01/jsf01.html http://www.atmarkit.co.jp/fjava/special/jsf02/jsf02_01.html 注3) 御本家のコンポーネントガイド (実際は改行なし) http://www.macromedia.com/jp/software/flash/productinfo/features/ mx/10application_development.html その他のサイト http://www.flashcomponents.net/ 注4) 「PowerGres on Linux」「PowerGres Plus」 http://www.zdnet.co.jp/news/0308/07/nj00_srasql.html 注5) PostgreSQL7.3インストール編 http://osb.sra.co.jp/PostgreSQL/7.3/install.html 注6) 「ツボによく利くJAVA & DB」(#010) SQL の 使いこなし 実例 http://www.melma.com/mag/02/m00020302/a00000226.html 注7) 郵便番号ダウンロードサイト 旧 http://www.post.yusei.go.jp/newnumber/down_2.htmhttp://www.post.yusei.go.jp/zipcode/download.html 注8) CSE Common SQL Environment http://www.hi-ho.ne.jp/tsumiki/ 【プロフィール】 福井 修 ( FUKUI Osamu )o-fukuiアットpo.iijnet.or.jp 福井システムリサーチ http://fsys.net/ 主幹。システム構築歴27年。 システム構築エキスパート 日本リヌクス協会、神戸商工会議所情報処理学会 会員 関西ソーホ・デジタルコンテンツ事業協同組合デジタルハリウッド三宮校 Java講師