IISサイト/マルチアプリケーション環境とRailsのURL (stylesheet編)

前回のエントリで完璧かと思われた、IIS7-FastCGI サイト/まね値アプリケーション環境におけるRailsアプリケーションのホスティングだが、まだ抜け穴があった。
いそいそとscaffoldを作り直して、できたアプリケーションのテストをしていた所、IISのログ(IIS形式)に以下のように出力された。

1, -, 1/28/2009, 14:35:46, W3SVC2, HOSTNAME, ::1, 46, 540, 244, 304, 0, GET, /addressbook/people/, -,
1, -, 1/28/2009, 14:35:46, W3SVC2, HOSTNAME, ::1, 0, 552, 5805, 404, 2, GET, /stylesheets/scaffold.css, 1233019499,

がーん。ビュー中のスタイルシートが読めていない。
Railsのscaffoldingで生成されたビューのスタイルシートへのリンクを生成する部分は以下のようになっている。

  <%= stylesheet_link_tag 'scaffold' %>

引数はスタイルシートのベース名だ。実際には.css+アセットが付加されるため、HTMLとしてのリンクは以下のようにレンダリングされる。

  

問題はやはりURLで、この場合もプレフィクス、今回の場合'/addressbook'が先頭に付加されないのが原因だ。
前回のエントリでは、routes.rb中のresourcesメソッドでRESTfulリソースを生成する際に'path_prefix'オプションを付加することで対応したが、stylesheet_link_tagはこの影響を受けないようだ。
このメソッド(JSPに慣れた身には、これはマークアップなのだとどこかで思ってしまうのが悲しい)、どこにあるのかと調べてみたのだが、ActionView::Helpers::AssetTagHelperというモジュールのようだ。
module ActionViewHelpersAssetTagHelper

#asset_tag_helper.rb
409  joined_stylesheet_name = (cache == true ? "all" : cache) + ".css"
410  joined_stylesheet_path = File.join(STYLESHEETS_DIR, joined_stylesheet_name)

これはスタイルシートへのパスを構成していね箇所だが、パスはSTYLESHEETS_DIRという定数を使っている。こいつはどこに定義されているのだろう。

#$RUBY_HOME\lib\ruby\gems\1.8\gems\actionpack-2.2.2\lib\action_view\helpers\asset_tag_helper.rb

115  ASSETS_DIR      = defined?(Rails.public_path) ? Rails.public_path : "public"
116 JAVASCRIPTS_DIR = "#{ASSETS_DIR}/javascripts"
117 STYLESHEETS_DIR = "#{ASSETS_DIR}/stylesheets"
118 JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'].freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)

なるほど、Rails.public_pathが定義されている場合はそれを使うと。Rails.public_pathはRailsアプリケーションのルートがセットされているはずだが、この値はRailsが初期化した時である。従って、stylesheet_link_tagのべースになるURLはビューがレンダリングされる際にルートを基点に評価されるのではなく、Railsが初期化した時点で決まっているということなのだろう。

であれば、routes.rbではなく、environment.rb等で直接環境変数か、間接パスを修正してしまえば良い。

#RAILS_ROOT\config\environment.rb
〜
ActionController::AbstractRequest.relative_url_root = '/addressbook'
[EOF]

(なお、routes.rbは元に戻しておかないと、プレフィクスが重複するので注意。)

これでstylesheet_link_tag、javascript_include_tag等の静的なURLをレンダリングするメソッドもアプリケーションのプレフィクスを付加することができた。

  

Railsのサーバとしてよく使われるMongrel※は開始時のオプションとしてプレフィクスを指定できるらしいが

mongrel_rails start --prefix /addressbook

例えばエントリポイントとなるスクリプトで同じオプションを読み込んで、上記パスに設定後dispatch.fcgiに処理を移すようにすれば、元のスクリプトに手を入れずにFastCGI経由で動作する時でもアプリケーション毎に簡単にプレフィクスを設定できそうだ。今度やってみよう。

※名前が洒落ているよな。"Mongrel"なんてぴったりなんだ。