前回の「erubyをERBに置き替える その1」では、Rubyに付属しているerbコマンドを使って、無理やりeRubyファイルをCGI化してみました。

一般的には、eRubyで書いたファイルとは別に、それを解釈するCGIスクリプトを用意しておいて、Apacheの設定でファイルをCGIに食わせる方法を取るようです。掌田津耶乃のさんの「ERBによるWebアプリケーション開発」という解説が分かりやすかったので、これに従って試してみました。

まず、.htaccessにAddTypeとActionディレクティブを書いて、拡張子「.rhtml」のファイルが「/ruby.cgi」で処理されるように設定します(もちろん、httpd.confの該当<Directory>に直接書いてもOKです)。

AddType application/x-httpd-eruby .rhtml
Action application/x-httpd-eruby /ruby.cgi

次に、「ruby.cgi」ファイルを作って下記の内容を記載し、実行権限を付与します。

#!/usr/local/bin/ruby
require 'erb'
require 'cgi'
puts 'Content-Type: text/html; charset=utf-8'
puts
ERB.new(IO.read(CGI.new.path_translated)).run

「fruits.rhtml」ファイルを作り、eRuby形式で中身を記載します。ひとまず、前回うまく行った「むりやり版」から、shebangと「_erbout = ““」とHTTPレスポンスヘッダを取り除いた形にしてみます。

<%
itemList = []
File.foreach("list.db") do |line|
  line.chomp!
  itemList.push(line)
end
%><html>
 <body>
% itemList.each do |item|
  <p><%=item%></p>
% end
 </body>
</html>

ここで読み込んでいる「list.db」の中身は前回と同じです。

りんご
みかん
バナナ

で、早速ブラウザからこの「fruits.rhtml」にアクセスしてみると、Internal Server Errorが出てしまいました。

[Sun Feb 23 19:56:40.317826 2014] [core:alert] [pid 1576] [client 12.34.56.78:12345] /path/to/the/doc/.htaccess: Invalid command 'Action', perhaps misspelled or defined by a module not included in the server configuration

.htaccessに書いたActionディレクティブがエラーになっているようです。Apacheのマニュアルによると、Actionディレクティブを使うためには、mod_actionsをロードする必要があります。デフォルトのhttpd.confでは下記の行がコメントアウトされているので、#を取って有効化します。

LoadModule actions_module libexec/apache24/mod_actions.so

Apacheを再起動し、再びブラウザで「fruits.rhtml」にアクセスすると、Internal Server Errorは出なくなったものの、今度は真っ白なページが表示されてしまいました。Apacheのエラーログに何か出ています。

[Sun Feb 23 20:00:56.582875 2014] [cgi:error] [pid 1620] [client 12.34.56.78:12345] AH01215: (erb):10:in `<main>': undefined local variable or method `item' for main:Object (NameError)
[Sun Feb 23 20:00:56.583277 2014] [cgi:error] [pid 1620] [client 12.34.56.78:12345] AH01215: \tfrom /usr/local/lib/ruby/1.9/erb.rb:838:in `eval'
[Sun Feb 23 20:00:56.583385 2014] [cgi:error] [pid 1620] [client 12.34.56.78:12345] AH01215: \tfrom /usr/local/lib/ruby/1.9/erb.rb:838:in `result'
[Sun Feb 23 20:00:56.583434 2014] [cgi:error] [pid 1620] [client 12.34.56.78:12345] AH01215: \tfrom /usr/local/lib/ruby/1.9/erb.rb:820:in `run'
[Sun Feb 23 20:00:56.583487 2014] [cgi:error] [pid 1620] [client 12.34.56.78:12345] AH01215: \tfrom /path/to/the/doc/ruby.cgi:6:in `<main>'

fruits.rhtmlの10行目で、itemが未定義だと言ってるようです。どうやら、この方式では行頭が%の行がRubyスクリプト片として認識されていないみたいです。なので、「% xxx」の行を「<% xxx %>」に変更してみます。

<%
itemList = []
File.foreach("list.db") do |line|
  line.chomp!
  itemList.push(line)
end
%><html>
 <body>
<% itemList.each do |item| %>
  <p><%=item%></p>
<% end %>
 </body>
</html>

もう一度「fruits.rhtml」にアクセスすると、今度は正常に画面が表示されました。HTMLのソースはこんな感じです。

<html>
 <body>

  <p>りんご</p>

  <p>みかん</p>

  <p>バナナ</p>

 </body>
</html>

行頭%の行は出力からは完全抹殺されていたのに対して、<% %>だと末尾の改行は残るので、間に空行が入っています。それ以外は特に問題ありません。

なお、実際には前回と同様、エンコーディングをきちんと合わせておかないと、エラーや文字化けの原因になるので、その辺を考慮するとこんな感じになります(スクリプト自体にも仮名漢字を入れてみました)。

<%# coding: UTF-8 %>
<%
itemList = []
File.open("list.db", "r:utf-8") do |file|
  file.each() do |line|
    line.chomp!
    itemList.push(line)
  end
end
%><html>
  <body>
  <h1>果物リスト</h1>
<% itemList.each do |item| %>
  <p><%=item%></p>
<% end %>
  </body>
</html>

これで、複数のeRubyファイルが簡単に作れるようになりました。

※バージョンメモ

  • FreeBSD 10.0-RELEASE-p0 amd64
  • ruby-1.9.3.484_1,1
  • apache24-2.4.6_1

※更新履歴

  • 2014-04-20 最後の例から「line.encode(Encoding::UTF_8)」の行を削除。