Nvu と CGIKit2 による Web アプリケーション開発

概要

今回は Nvu という HTML オーサリングツールと CGIKit を使って Web アプリケーションを作ってみます。 Nvu を使えば HTML デザイナーの方が作った HTML を ほぼ無修正で CGIKit から利用することも可能です。

筆者はデザインが得意ではないので、これを読んだ皆さんが Nvu を使って色々とデザインしてくれることを期待しています。

対象とする読者

  • Ruby がそれなりに分かる方
  • CGIKit-2.x のるびま記事を読んだ方
    • CGIKit の wiki のチュートリアルをやった方でも結構です。
  • Nvu に興味のある方
  • HTML の知識がそれなりにある方
    • CSS の知識があると良いですが、必須ではありません。

必要なもの

  • Ruby-1.8.2
    • 標準添付されている WEBrick、 REXML
  • cgikit-2.0.0-preview1
  • Nvu-1.0
  • サンプルのソース rubima-ck0009.zip

CGIKit のインストールの方法については 前々回の記事CGIKit の Wiki を参照してください。

Nvu に関しては Windows で動作確認をとっていますので、 同じ環境で試すことをお勧めします。

Nvuってなあに?食べ物?

… Nvu は食べ物じゃないです。 Nvuのサイト に書かれているように Nvu は Windows, Mac, Linux で動く WYSISYG(What you see is what you get の略) な HTML の オーサリングツールです。 ちなみに Nvu の読み方は New View という意味を込めて「エヌビュー」らしいです。

スクリーンショット demo.jpg

Nvu には様々な特徴がありますが、 http://www.nvu.com/features.html に書かれているものから抜粋して 下に載せます。

  • レンダリングに Gecko を使用
  • CSS Editor(CaScadeS)
  • ユーザーインターフェースの改良(タブ、色選択ダイアログ、ツールバーなど)
  • Markup Cleaner
  • FTP サイトの管理機能

上の中には含まれていませんが、CGIKit-2.x を使う立場から Nvu を見ると、 XHTML のサポートという点が大きいです。 CGIKit-2.x ではXHTML (正確には XML と言うべきですが) を使用しますので、 Nvu の XHTML サポートとは相性が良い(はず)です。

Nvu の インストール・起動・設定 については本文とは関係ないので、 別ページに分割しています。詳細は 今号のCGIKit2の付録ページ へどうぞ。

サンプルの説明をそろそろはじめろよー。

はいはい、分かりましたよ。急かさないで下さい。 今回はサンプルとしてユーザー登録ページを作ります。 ページの流れは下のようになります。

 登録のお願い          (index.html)
    |
    ↓
ユーザー情報入力 ←┐  (Registration::RegisterPage)
    |↑   │      │
    ↓|   └───┘
  入力確認             (Registration::ConfirmPage)
    |
    ↓
登録終了のお知らせ     (Registration::ThanksPage)

各ページの HTML の大部分を Nvu で作ります。 そのため CGIKit や Ruby と関係のない部分が多くなりますが、ご了承ください。

Registration プロジェクト - 初めの一歩?

最初に Registration プロジェクトを作ります。 前回の記事と同じように

 ruby ckproject Registration

として Registration プロジェクトを作ります。 Windows では which コマンドが無いためエラーになることがあります。

``': No such file or directory - which ruby (Errno::ENOENT)

この場合は whichコマンドを作る を参考にして which.bat を ckproject と同じフォルダーに 置いてから実行してみてください。

ckproject が終了すると、 Registration というフォルダーができます。 この時にいっしょに Registration の中に www というフォルダーを作っておきます。 この中には CSS やテンプレートではない 普通の HTML が保存されることになります。

Registration.rb - WEBrick 起動スクリプト

今回も WEBrick で開発します。起動用スクリプトは Registration/Registration.rb です。 起動方法は今までといっしょで Registration フォルダーに移動して

 ruby Registration.rb

とします。One-Click Installer for Windows を 使用されている場合は Registration.rb をダブルクリックして 起動することも可能です。

   1|#!/usr/bin/ruby
   2|
   3|# Registration.rb [port]
   4|
   5|$LOAD_PATH.unshift('lib')
   6|require 'webrick'
   7|require 'cgikit'
   8|require 'cgikit/webrick'
   9|require 'application'
  10|require 'session'
  11|require 'directaction'
  12|require 'kconv'
  13|
  14|module Registration
  15|  
  16|  module UserInfo
  17|    attr_accessor :name, :age, :sex, :year, :month, :day, :address, :phone
  18|    
  19|    def to_utf8
  20|      @name = Kconv.toutf8(@name)
  21|      @age = Kconv.toutf8(@age)
  22|      @sex = Kconv.toutf8(@sex)
  23|      @year = Kconv.toutf8(@year)
  24|      @month = Kconv.toutf8(@month)
  25|      @day = Kconv.toutf8(@day)
  26|      @address = Kconv.toutf8(@address)
  27|      @phone = Kconv.toutf8(@phone)
  28|    end    
  29|  end
  30|  
  31|  def self.copy_info(from, to)
  32|    to.name = from.name
  33|    to.age = from.age
  34|    to.sex = from.sex
  35|    to.year = from.year
  36|    to.month = from.month
  37|    to.day = from.day
  38|    to.address = from.address
  39|    to.phone = from.phone
  40|  end
  41|  
  42|end
  43|
  44|
  45|port = (ARGV.shift || 8080).to_i
  46|
  47|app = Registration::Application.new
  48|app.load_all_components('./components')
  49|app.load_configuration('./cgikitconf.rb')
  50|app.main = Registration::RegisterPage
  51|
  52|server = WEBrick::HTTPServer.new({:Port => port})
  53|server.mount('/', WEBrick::HTTPServlet::FileHandler, "www")
  54|server.mount('/register.cgi', WEBrick::CGIKitServlet::ApplicationHandler, app)
  55|
  56|trap("INT"){ server.shutdown }
  57|server.start

各ページを作る前に ckproject が作ったスクリプトにいくつか修正を加えます。 一つ目は Kconv を使えるように require 'kconv' を追加することです。 Kconv は後で文字コードの推定・変更のために利用します。 二つ目は Registration::UserInfo と Registration.copy_info を定義することです。 前者はページ間でやり取りされるユーザー情報で、 後者はそのデータをコピーするためのクラスメソッドです。 後者はもう少しスマートに定義することができますが、 コードが読みにくくなるので今回は泥臭く定義します。 三つ目は URL と表示する内容の関連付けです。 下の部分が関連付けを行う部分です。

server.mount('/', WEBrick::HTTPServlet::FileHandler, "www")
server.mount('/register.cgi', WEBrick::CGIKitServlet::ApplicationHandler, app)

URL の / は Registration.rb 実行時の Registration/www フォルダーに関連付けられ、/register.cgi は コンポーネントを表示するページに関連付けられます。

最後の4つ目は /register.cgi で表示されるコンポーネントの指定です。 実際に指定しているのは46行目の下の部分です。

 app.main = Registration::RegisterPage

前回までに説明したように CGIKit::Application#main に表示させたい コンポーネントのクラスを指定します。

index.html - スタート地点だね

最初に作るのは普通の HTML です。 このページが登録ページのスタートになります。

ここから実際に Nvu を使って HTML を作っていきます。 Nvu の使い方は簡単です。 Microsoft Word や OpenOffice のような ドキュメント作成ツールと同じように文章を入力するだけです。 Nvu は HTML オーサリングツールとしては比較的まともな HTML を生成してくれるので、 Nvu で作った HTML を手で修正するのも容易です。

初めにメニューの File -> New から 新しいページを作ります。 下のようなダイアログが現れるので、create a XHTML document にチェックが 入っていることを確認してから Create のボタンを押してください。

nvu_file_new.jpg

次に index.html として保存します。メニューの File -> Save を選ぶと タイトルを聞かれるので、適当にタイトル名をつけます。

nvu_file_save.jpg

保存先は先ほど作った Registration/www です。 index.html として保存します。

最後に本文と登録ページへのリンクを作ります。 リンク(aタグ)は Insert -> Link から挿入します。 リンク先は /register.cgi とします。

nvu_insert_link.jpg

リンクを挿入した後に細かい修正を行って、下の図のようにします。 この図は HTML のソースを手動で編集するモードになっています。 Nvu の下にある Source というタブがあり、これをクリックすることで ソースを直接編集するモードになります。 元のモードに戻したい場合は Normal を押します。

index_page.jpg

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja"><head>

  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  


  <title>CGIKit2 デモ</title><link rel="stylesheet" href="index.css" type="text/css" /></head>

<body>

これはCGIKit2のデモページです。<br />

<br />

良かったら、下のリンクをたどってユーザー登録してください。ぺこぺこ。<br />

<br />

<div id="register-box">
<a href="/register.cgi" id="register-link">登録ページへ</a>
</div>

</body></html>

これで少しは Nvu に馴れたでしょうか? デザインは CGIKit と関係ないので、ここでは扱いません。 付録ページに CSS を 使ってデザインする方法を説明していますので、 興味のある方はそちらをご覧ください。

Registration::RegisterPage - そろそろ Ruby のプログラムを書けよー

そうですね。CGIKit の記事なのですから、いい加減 Ruby のコードを 書かないと怒られてしまいますね。とはいえ、最初は Nvu で HTML を作ります。 ユーザー情報の登録ページなので、

  • 名前
  • 性別
  • 年齢
  • 生年月日
  • 住所
  • 電話番号

を入力するためのフォームを作り、 いっしょにエラーメッセージも入れます。 HTMLが一区切りついたら、それに Nvu で CGIKit と連携させるための 修正を少し加えます。後は前回までの記事と同様に *.ckd や *.rb に Ruby のコードを書いていくだけです。

RegisterPage.html

Nvu を使ってテンプレート(HTML)を作成します。 index.html と同じようにして新しい HTML を作り、 RegisterPage.html として Registration/components 以下に保存します。

次にフォームを挿入します。 Form のボタンを押すかメニューの Insert -> Form -> Define Form で下の図のようなダイアログを表示させます。 何か入力しても良いのですが、後で CGIKit によって上書きされるので、 何も入力せずに OK を押します。alert が出ますが、無視して挿入します。

nvu_form.jpg

次に名前を入力するテキストフィールドを作ります。 フォームが水色の破線で表されているので、その中に 「名前」と入力します。そして、その後ろにテキストフィールドを挿入します。 Insert -> Form -> Form Field を選ぶと、ダイアログが出現します。 Field Type に Text を選択し、name 属性を適当に入力します。 name 属性を設定しないと、OKが押せませんので注意してください。

nvu_textfield.jpg

以下、同じ要領で Nvu に入力していきます。 おおよそ下のような図になるようにします。

nvu_regsiter_page1.jpg

性別に関しては Insert -> Form -> Form Field で Field Type に Radio Button を選択します。 OK ボタンを挿入するには Insert -> Form -> Form Field -> Submit Button を選んで Name Value に「OK」 を入力します。

「ユーザー情報」「名前」などを目次として扱いたい場合は Heading である h1 や h2 タグを使います。目次にしたい部分を選んで、 アイコンの列の下にある Body Text の部分を好みの Heading に変えてください。 Heading 1 は h1 タグに、Heading 2 は h2 に対応します。

フォームが完成したら、各項目にエラーメッセージを挿入します。

CGIKit のテンプレートへ

ここから CGIKit のテンプレートとして使用できるように HTML を直接修正します。注意する点は下の 2 点です。

  • form, input タグに ckid 属性を設定し、name 属性を削除
  • エラーメッセージを ckid 属性の付いた span タグで囲う

name 属性は自分で付けても良いのですが、重複してはいけません。 重複させる不安があるのならば name 属性を消去したほうが無難でしょう。 name 属性が無い場合は 実行時に CGIKit が自動的に割り振ってくれます。

また、デザイン用にいくつかの div を追加します。 修正の結果、最終的に下のようになります。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja"><head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" /><title>ユーザー情報</title>
<link rel="stylesheet" href="/register.css" type="text/css" /></head>
<body>
<h1>ユーザー情報</h1>
<form ckid="form">
<div class="item"><h2>名前</h2>
<input ckid="name" /> <span ckid="error_name">名前が空白です。</span> 
</div>

<div class="item"><h2>性別</h2>
<input ckid="male" value="b" type="radio" />男性
<input ckid="female" value="d" type="radio" />女性 
<span ckid="error_sex">性別が選択されていません。</span>
</div> 

<div class="item"><h2>年齢</h2>
<input ckid="age" /><span ckid="error_age">適切な年齢ではありません。</span>
</div>

<div class="item"><h2>生年月日</h2>
<input ckid="year" />年 <input ckid="month" />月 <input ckid="day" />日<br />
<span ckid="error_date">適切な生年月日を入力してください。</span>
</div>

<div class="item"><h2>住所</h2>
<input ckid="address" /> <span ckid="error_address">住所が空白です。</span>
</div>

<div class="item"><h2>電話番号</h2>
<input ckid="phone" /> <span ckid="error_phone">電話番号に入力できるのは数字とハイフン(-)のみです。</span>
</div>

<br/>

<div class="ok"><input ckid="submit" value="OK" type="submit" /></div>
</form>

</body></html>

編集が完了したら修正した部分が 正しいのかどうかを ckparse を使って検証します。

 ruby ckparse Registration/components/RegisterPage.html

下のように出力されたら文法的には OK です。失敗したら ckparse のエラーメッセージを見たり、 Nvu の メニューから Tools -> Validate HTML で XHTML として適合するかどうか チッェクしたりしてください。

#<CGIKit::HTMLParser::RootNode:0x1016fa18
 @content="",
 @name="",
 @node=
  [#<CGIKit::HTMLParser::TextNode:0x100c6bd0
    @content=
     "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transiti...

ckparse の出力から ckid 属性が正しく付加されているかどうかもチェックできますので、 興味のある人は試してみてください。

RegisterPage.ckd

次に RegisterPage.ckd を作ります。

   1|{
   2|  :form => {
   3|    :element => Form,
   4|  },
   5|  
   6|  :name => {
   7|    :element => TextField,
   8|    :value => :name,    
   9|  },
  10|  
  11|  :male => {
  12|    :element => Radio,
  13|    :name => "sex",
  14|    :selection => :sex,
  15|    :value => "M"
  16|  }, 
  17|  
  18|  :female => {
  19|    :element => Radio,
  20|    :name => "sex",
  21|    :selection => :sex,
  22|    :value => "F"
  23|  },
  24|  
  25|  :age => {
  26|    :element => TextField,
  27|    :value => :age,
  28|  },
  29|  
  30|  :year => {
  31|    :element => TextField,
  32|    :value => :year,    
  33|  },
  34|  
  35|  :month => {
  36|    :element => TextField,
  37|    :value => :month,    
  38|  },
  39|  
  40|  :day => {
  41|    :element => TextField,
  42|    :value => :day,    
  43|  },
  44|  
  45|  :address => {
  46|    :element => TextField,
  47|    :value => :address,    
  48|  },
  49|  
  50|  :phone => {
  51|    :element => TextField,
  52|    :value => :phone,    
  53|  },
  54|  
  55|  :submit => {
  56|    :element => Submit,
  57|    :action => :next_page
  58|  },
  59|  
  60|  
  61|  
  62|  
  63|  :error_name => {
  64|    :element => Conditional,
  65|    :condition => :error_name,
  66|  },
  67|  
  68|  :error_age => {
  69|    :element => Conditional,
  70|    :condition => :error_age,
  71|  },
  72|  
  73|  :error_sex => {
  74|    :element => Conditional,
  75|    :condition => :error_sex,
  76|  },
  77|  
  78|  :error_date => {
  79|    :element => Conditional,
  80|    :condition => :error_date,
  81|  },
  82|  
  83|  :error_address => {
  84|    :element => Conditional,
  85|    :condition => :error_address,
  86|  },
  87|  
  88|  :error_phone => {
  89|    :element => Conditional,
  90|    :condition => :error_phone,
  91|  },
  92|}

前回までの記事で説明した部分がほとんどです。 基本的に HTML のタグに対応するエレメントを HTML に割り振っていきます。 たとえば、input の type 属性の指定無しであれば TextField エレメント、 input type="submit" なら Submit エレメントという感じです。

今回新しく使うエレメントは Radio です。 Radio によってグループ化されたボタンは その中の一つだけ選択することが出来ます。 Radio の設定部分を下に載せます。

 :male => {
   :element => Radio,
   :name => "sex",
   :selection => :sex,
   :value => "M"
 },

 :female => {
   :element => Radio,
   :name => "sex",
   :selection => :sex,
   :value => "F"
 },

male, female の ckid 属性が付いているのは RegisterPage.html の input タグの radio です。 男性と女性を選択する部分ですね。

この二つをグループ化するには二つの Radio エレメントに同じ name 属性を与えます。 上の例では sex という名前でグループ化しています。 選択されたときに使用されるデータは selection と value で指定します。 value は選択されたときに代入される値で、 selection はその値が代入されるメソッド名(もしくはインスタンス変数)です。

この ckd ファイルの設定で OK ボタンが押されると、 Registration::RegisterPage#sex に 男性なら "M" が 女性なら "F" が代入されます。

これ以外のエレメントについては過去の記事に説明があります。 付録ページでも説明していますので、 気になる方はそちらをご覧ください。また、CGIKit で使用する HTML の説明も ありますので、合わせて読んでみてください。

RegisterPage.rb

最後に RegisterPage.rb です。 ここにコンポーネントのクラスを定義します。

   1|require 'date'
   2|
   3|module Registration
   4|    
   5|  class RegisterPage < CGIKit::Component
   6|    
   7|    include UserInfo
   8|    
   9|    def next_page
  10|      to_utf8
  11|      
  12|      @error_name = (@name.to_s == "")
  13|      @error_age = (/\A\d+\z/ !~ @age.to_s )
  14|      @error_sex = (/\A[MF]\z/ !~ @sex.to_s)      
  15|      @error_address = (@address.to_s == '')
  16|      @error_phone = (/\A[0-9-]+\z/ !~ @phone.to_s )
  17|      
  18|      y = @year.to_i
  19|      m = @month.to_i
  20|      d = @day.to_i
  21|      @error_date = false
  22|      begin
  23|        Date.new(y,m,d)
  24|      rescue ArgumentError
  25|        @error_date = true
  26|      end
  27|      
  28|      error = @error_name || @error_age || @error_sex || @error_address || @error_phone || @error_date      
  29|      unless error
  30|        p1 = page(ConfirmPage)
  31|        Registration.copy_info(self, p1)
  32|        p1
  33|      end
  34|    end
  35|    
  36|  end
  37|  
  38|end

今までと同じように CGIKit::Component を継承しています。 これはコンポーネントを作る際に必須になります。 CGIKit::Component を継承しないと コンポーネントとして使えませんので注意してください。

Registration::UserInfo

RegisterPage は Registration::UserInfo を include しています。 これはユーザーが入力した情報を各ページで 参照・変更を可能にするためのモジュールです。 UserInfo にはアクセサと to_utf8 という文字コード変換の ためのメソッドがあるだけで、機能としては単純です。 コードについてはすでに Registration.rb で出てきていますので、 そちらをご覧下さい。

UserInfo#to_utf8 は入力データの文字コードを UTF-8 に変換します。 UTF-8 への変換のために Registration::UserInfo#to_utf8 では Kconv#toutf8 を用います。

*1

今号の 標準添付ライブラリ紹介【第 3 回】Kconv/NKF/Iconv には Kconv/NKF の紹介があります。Ruby-1.8.2 に付属する Kconv/NKF のバグについても説明されていますので、一読されることをお勧めします。

Kconv の代わりに Uconv, Iconv で文字コード変換を したい人はそれでも結構です。 CGIKit では rbuconv が同梱されているので、 Kconv の代替には Uconv を使うことをお勧めします。

Registration::RegisterPage#next_page

サブミットボタンが押されたときに実行されるメソッドです。 内容はエラーチェックと次のページへの移動です。 以前説明したようにフォームに入力されたデータは RegisterPage に戻ってきて、そこで next_page が実行されます。 next_page が実行されるときには CGIKit によって 変数にフォームのデータが自動的に入っています。

エラーチェックは 12-26 行で行われています。 ここでは入力内容が適切かどうかを正規表現や Date クラスでチェックします。 エラーがあると該当部分の @error_... に true が代入されます。 エラーチェックの結果一つでもエラーがあると、 error というローカル変数が true になります。 最終的にこの error が表示されるページを決定します。 @error_... は Conditional エレメントの condition 属性に 指定されているので、@error_... に true が代入されると 最初に表示されなかったエラーメッセージが表示されるようになります。

error が false であれば、 29-33行で次のページになる Registration::ConfirmPage の オブジェクトが作られ、 入力された情報がコピーされて next_page の返り値になります。 こうすることで CGIKit が今作った Registration::ConfirmPage を表示してくれます。 もし、error が true であれば、next_page の返り値がないため そのまま self(Registration::RegisterPage) が表示されます。 すでに紹介したように self には 各項目についてエラーの有無が設定されていて、 それに基づいて Conditional エレメントがエラーメッセージを表示します。 また、ユーザーが入力した情報はエラーがあってもそのままフォームに表示されます。

例えば、名前だけを空欄にしたまま OK ボタンを押すとします。 こうすると、@error_name が true になり、next_page の返り値が self(Registration::RegisterPage) になります。 この時、それまで入力されていた内容が CGIKit によって フォームに表示され、いっしょに @error_name に対応する 名前のエラーメッセージも表示されます。

スクリーンショット

CSS でデザインしてこんな感じなります。

registerpage.jpg

Registration::ConfirmPage - 確認、確認、確認

RegisterPage で入力された内容をチェックするページです。 Registration::RegisterPage#next_page で入力情報が Registration::ConfirmPage のオブジェクトにコピーされています。 そのデータに基づいて入力情報確認用のフォームを表示させます。

ここで重要になるのは下の2点です。

  • 入力情報を表示させること
  • その情報を次のページに渡すこと

ConfirmPage.html

テーブルとフォームを使って RegisterPage で入力された内容を表示させます。 HTML は Nvu で作りますが、ここでもフォームを使います。 CGIKit ではフォームを使う方がデータを簡単に次のページに渡すことができます。

最初にフォームを作って、その中にテーブルを入れます。 Nvu でテーブルを作るには Table ボタンを押すか、メニューの Insert -> Table を選択します。

nvu_table.jpg

上図ようなダイアログが現れるので、6x2 のテーブルを作ります。 テーブルの各セルには入力データの種類の名前とその内容を 表示するテキストフィールドを入力します。 それに加えてテーブルの下に二つのサブミットボタンを追加します。 以上で下のような図になると思います。 (この図では CSS で装飾を加えています)

nvu_confirm.jpg

このままだと、各フィールドの内容をユーザーが自由に修正できます。 そのため HTML タグの readonly 属性を使って 修正を不可能にしなければなりません。 各フィールドを選択して右クリックするとメニューが出現します。 その中に Form Field Properties という項目があり、 これをクリックするとフィールドの設定を行うことが出来ます。 readonly というチェックがあるので、 ここをチェックして readonly 属性を設定します。

nvu_field_prop.jpg

この後は RegisterPage.html のように ckid 属性を付けていきます。 下に修正後の HTML のソースを載せます。この HTML には簡単に CSS も記述してあります。

<html xmlns="http://www.w3.org/1999/xhtml" lang="ja"><head><meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<title>確認</title>
<style type="text/css">
td { padding-top: 0.4em;
padding-left: 0.4em;
padding-bottom: 0.4em;
}
table { background-color: rgb(255, 255, 181);
}
</style>
</head>
<body>
<h1>確認ページ</h1>
<form ckid="form"> <table border="4"><tbody>
<tr><td>名前</td> <td><input readonly="readonly" ckid="name" /></td></tr>
<tr> <td>性別</td> <td><input readonly="readonly" ckid="sex" /></td> </tr>
<tr> <td>年齢</td> <td><input readonly="readonly" ckid="age" /></td> </tr>
<tr> <td>生年月日</td> <td><input readonly="readonly" ckid="year" />年 <input readonly="readonly" ckid="month" />月 <input readonly="readonly" ckid="day" />日</td> </tr>
<tr> <td>住所</td> <td><input readonly="readonly" ckid="address" /></td> </tr>
<tr> <td>電話番号</td> <td><input readonly="readonly" ckid="phone" /></td> </tr>
</tbody> 
</table> 
登録情報はこれで正しいですか? <br />
<input value="OK" ckid="ok" type="submit" /><input value="戻る" ckid="back" type="submit"/>
</form>
</body></html>

ConfirmPage.ckd

   1|{
   2|  :form => {
   3|    :element => Form,
   4|  },
   5|  
   6|  :name => {
   7|    :element => TextField,
   8|    :value => :name,
   9|  },
  10|  
  11|  :sex => {
  12|    :element => TextField,
  13|    :value => :sex,
  14|  }, 
  15|  
  16|  :age => {
  17|    :element => TextField,
  18|    :value => :age,
  19|  },
  20|  
  21|  :year => {
  22|    :element => TextField,
  23|    :value => :year,
  24|  },
  25|  
  26|  :month => {
  27|    :element => TextField,
  28|    :value => :month,
  29|  },
  30|  
  31|  :day => {
  32|    :element => TextField,
  33|    :value => :day,
  34|  },
  35|  
  36|  :address => {
  37|    :element => TextField,
  38|    :value => :address,
  39|  },
  40|  
  41|  :phone => {
  42|    :element => TextField,
  43|    :value => :phone,
  44|  },
  45|  
  46|  :ok => {
  47|    :element => Submit,
  48|    :action => :next_page
  49|  },
  50|  
  51|  :back => {
  52|    :element => Submit,
  53|    :action => :prev_page
  54|  },
  55|
  56|}

ConfirmPage.ckd と RegisterPage.ckd はほとんど同じです。 説明の必要は無いでしょう。

でも、ConfirmPage.ckd を作るのは面倒ではないでしょうか? ConfirmPage.ckd と RegisterPage.ckd がほとんど同じであれば RegisterPage.ckd の内容を ConfirmPage.ckd に渡せたらと 思うのは自然なことです。

結論から言えば ckd の内容を共有することは可能です。 それには付録ページで述べた Ruby スクリプトに ckd ファイルの内容を 混ぜるという方法を使います。 しかし、この機能は CGIKit-2.0.0-preview1 では使わない方が無難なので、 ここでは紹介しません。興味のある方は挑戦してみてください。 この記事では RegisterPage.ckd の内容を ConfirmPage.ckd にコピーして から手動で修正をするという方法を取りました。

ConfirmPage.rb

   1|module Registration
   2|  
   3|  class ConfirmPage < CGIKit::Component
   4|    
   5|    include UserInfo
   6|    
   7|    def next_page
   8|      to_utf8
   9|            
  10|      p1 = page(ThanksPage)
  11|      p1.name = self.name
  12|      p1
  13|    end
  14|    
  15|    def prev_page
  16|      to_utf8
  17|      
  18|      p1 = page(RegisterPage)
  19|      Registration.copy_info(self, p1)
  20|      
  21|      p1
  22|    end
  23|    
  24|  end
  25|  
  26|end

ここでは OK ボタンを押したときや 戻るボタン を押したときの挙動に関して 述べることにします。

OK ボタンや 戻るボタン には ConfirmPage.ckd で next_page と prev_page が action 属性に割り当てられています。 前者のメソッドは Registration::RegisterPage#next_page と同じく 入力データ(名前)を最終ページである Registration::ThanksPage のオブジェクトに コピーして、メソッドの返り値にしてページを表示させます。 後者のメソッドでは元のページに戻るために Registration::RegisterPage の オブジェクトを作って入力情報をコピーして prev_page のメソッドの返り値にします。

要するにページの移動は CGIKit のコンポーネントのオブジェクトを 渡してやれば良いわけです。 この時注意が必要なのは値の受け渡しです。 ConfirmPage.html でも述べたようにページ間のデータの受け渡しは フォーム(正確には Form エレメント)を介して行います。 注意してください。

スクリーンショット

confirmpage.jpg

ThanksPage - おしまいー

最後は入力された名前を表示させておしまいです。 新しいことは何も無いので、説明は省略します。

ThanksPage.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja">
<head><meta content="text/html; charset=UTF-8" http-equiv="content-type" /><title>Thanks</title> 
</head>
<body><span ckid="name">a</span>さん、ご登録ありがとうございました。</body>
</html>

ThanksPage.ckd

   1|{
   2|  :name => {
   3|    :element => String,
   4|    :value => :name
   5|  }
   6|}

ThanksPage.rb

   1|module Registration
   2|  
   3|  class ThanksPage < CGIKit::Component
   4|    
   5|    attr_accessor :name
   6|        
   7|  end
   8|  
   9|end

スクリーンショット

thankspage.jpg

宿題

  • ConfirmPage の性別の選択のところで男性は M が女性は F が表示されます。これを分かりやすい表示に変えてください。
  • 今回は WEBrick で開発しましたが、実行環境を CGI に変更してみてください。何に注意しなければならないでしょうか。
  • ThanksPage で表示されるページの内容が寂しいです。ConfirmPage#next_page の実装を変えて色々な入力データを ThanksPage に渡し、その情報に基づいて ThanksPage で表示させる内容を変えてみてください(例えば、誕生日石を表示させたり、占いを表示させたり)

謝辞

上記のサイトの管理者の皆様方には快くリンクの許可を頂きました。 本当にありがとうございました。

著者について

10月まで暇になってしまいました。暇にまかせてJavascript で遊んだり、 世界は残酷だなあとか訳のわからないことを考えたりしています。

私はあまり関係ないけど、Rails な人は Multilingual Rails で良いんですかね? 本家の ML でむとうさんが反対していますが、 あのまま広がると後で悲しくなりそうです。 (世界の片隅で私一人が心配しても何の影響力も無いですけどね・・・)


*1 本来であれば Kconv ではなく、NKF を直接使って文字コードの変換を行うべきです。しかし、それを行うと説明が冗長になること、標準添付ライブラリ紹介【第 3 回】に説明が載っているということ、を考え今回は割愛させていただきました。