Ruby Earrings
eRuby で遊ぶ

第4回 CGIスクリプトの分割

eRuby と直接関係はないデス

CGI でひとつのシステムを作る時、CGI はいくつ作りますか? ひとくちに CGI と言ってもいろいろありますが、掲示板で考えてみましょう。そのあたりの Perl の掲示板を見ていると、1つの CGI に、投稿も表示画面もエラー画面もなにもかももうゼンブゼーンブ、これでもかー! というくらい詰め込んであることが多いですよね。せいぜいのところ、管理画面だけ別だったりすることがある程度。

ひとつの CGI で全部やろうとすると、サイズが大きくなってしまって起動に時間がかかります。それだけでなく、保守性がとても悪いです。全部ひとつでやろうとするから、場合分け、場合分け、場合分け、この場合はこっち、あの場合はあっち。読もうと思っても、それを追うのだけで大変です。

詰め込んでしまう気持ちはよーくわかります。そうなるのには理由があります。CGI は仕組み上、リクエストに応じて作業をし、最後に何か表示する、ということになっています。その作業と表示が本当はあまり関連がなくてもです。そういう仕組みの上でモノを作ると、わざわざ分けようと思わない限り一緒になってしまいます。一緒にしはじめると、雪だるま式に全部同じスクリプトで済ませることに。作ったあと、あり? なんでこうなっちゃったんだろ? と呆然とすることになっているんですよね…。

たとえば、掲示板で必要なものは、最低次の3つの機能です。

ひとつの CGI で済ませる場合、処理の流れはこんな感じ。

普通は保存機能と表示機能を持つサブルーチンを作っておき、メインルーチンで投稿されたのかただの表示なのかを判別、ただの表示なら保存のところをスキップする、というような流れになると思います。で、なにかするたびに「エラーが起きたらエラー表示ルーチンを呼ぶ」みたいに書くわけです。

しかし。これが諸悪の根源。これをやり始めたが最後、全てがひとつのスクリプトになってしまうのです。この際、このパターンはやめましょう。それぞれを別の CGI にしたらどうなるか考えてみます。


eRuby + Ruby で CGI のシステムを作る

幸い、eRuby HTML は表示機能を担当する、というのがわかりやすいですから、表示は eRuby HTML, 表示以外は Ruby スクリプトの CGI にまかせることにしましょう。

表示するときはただ、表示する CGI にアクセスします。 投稿するときは、保存する CGI に記事データを渡します。保存する CGI は保存が終わったら、表示の CGI へ redirect します。 保存、表示ともに、どこかで例外が起こったらエラー表示の CGI へ redirect します。

こう分けると、それぞれの役割が明確で、保守性もよくなります。 (*1)

(*1) なんだか言い切ってますが、迷うところもあるんですよ。HTTP の仕様書(RFC) を読むと、POST メソッドのリクエストに対するレスポンスでは redirect せんほうがええよ〜、って書いてあるんです。でもそこには理由が書いてないので納得いかず、 POST に対しても redirect しちゃってます。うしろめたい思いのまま。クスン。誰かー。理由を教えてー。理由をー。でも理由教えてもらって納得しちゃったら、きっと redirect する気なくなるデスよね。そしたらそのあといったいわたしはどうスレバーー!! (ってそんなことまで知らんつーの)。どっちにしろすっきりせえへんねえ。


eRuby での redirect のしかた

さて、例外が起きたときに redirect しようとすると、ハテ。eRuby ではどうやって redirect するのだっけ。 CGI を書いたことがおありのかたは、第1回からずーっと気持ち悪かったと思います。「なんで HTTP ヘッダの出力してないの?」って。今までナイショにしていましたが、実は eruby が出力してくれています。eruby は CGI として起動されると HTTP body の前に自動的に Content-Type と Content-Length ヘッダを出力してくれるのです。わたくしのような横着モノにはかなり嬉しい親切設計。

でもでも、HTTP body だけ動的にしたい場合は嬉しい仕様なんですが、ヘッダコントロールをしようとするとちょっと困りますよね。んまぁワガママさんっ。しかし eruby はなんと、そんなワガママもニコニコしてきいてくれるのデシタ。キャー、eruby ステキ。男前! (念のため申し添えますが、実際は前田さんがきいてくださったんです。ありがとうございます)

eruby には noheader モードというのがあります。eruby からはヘッダは出さないよ、というモードです。つまりそのモードだと、ヘッダを自分で(eRuby HTML のほうで)出せるわけです。これを使います。eruby のコマンドラインオプションからモードを指定することもできますが、eRuby HTML 中から header/noheader モードを変更することができて嬉しいので、そちらを活用しましょう。

$NOHEADER = true

とすると noheader モードになります。redirect するには次のように書きます。

<%
begin
  処理とかHTML
rescue
  # clear output
  $>.cancel

  # noheader mode
  $NOHEADER = true

  # redirection
  print "Location: #{uri_for_error}\n\n"
end
%>

処理中に例外が起きたら今までに出力してしまった HTML をクリアして noheader モードに入り、redirect します。正常系のみで処理が完結した場合は header モードのままで eruby にヘッダを出してもらえますから、eRuby HTML ではヘッダは書かなくてもいいんですよ。

次回は、今回の枠組を踏襲して掲示板を作ってみます。(←お見せできるようなものがあるわけではないデス)

| prev || Ruby Earrings || next |

TAKEUCHi Kahori <takeuchi@kahori.com>