Rails3.1へのアップグレード

諸事情からRails3.0のアプリケーションを3.1にアップグレードした。 「簡単」と書かれていることが多く、Railsの流儀に則っていれば実際簡単なんだけど、それ以外の部分についてだいぶ手間取ったので書いておく。

まず、アプリケーション本体についてはASCIIcastの記事の通りにやれば問題ない。 ざっと書いておくと、 rails31ブランチを作成し、Gemfileを更新。 railsだけでなく、mysql2も最新にしておく。

# gem 'rails', '3.0.10'
gem 'rails', '3.1.3'
# gem 'mysql2', '< 0.3'
gem 'mysql2'

bundle updateしてdevelopment.rbの

# config.action_view.debug_rjs = true

をコメントにするだけでとりあえず動く。

もちろん、これだけでは肝心のassets pipelineを使っていないので、3.1の真価は発揮できない。 むしろ大変なのはここから。

今回のアプリケーションの場合、cssは全てデザイナーの作成したものをそのままpublic/stylesheetsに放り込んで使っていた。が、ご存じの通りassets pipelineを有効にするとstylesheetsやjavascriptsは単一のファイルに固められ、パスが変わるのでそのままでは運用できない。 まず、上記のASCIIcastにも書いてある通り、public/images、public/stylesheets、public/javascriptsをそれぞれapp/assets以下に移動する。

まずjavascriptsから。 読み込み順が指定されているものがあるので、application.jsの [javascript] //= require_tree . [/javascript] を [javascript] //= require_directory . [/javascript] に変更、後から読み込むものをapp/assets/javascripts/contrib/以下に配置して [javascript] //= require contrib/include_later.js [/javascript] 等で順序を固定できる。

stylesheetsはもうちょっと複雑で、backgroundでurlを指定している場合には全て書き換えなくてはならない。/imagesを/assetsにしても動くことは動くが、assets_pathヘルパを使うのが望ましい。 理想を言えばcssをscssに書き換えるべきだが、工数が増えすぎるので今回は見送り。 [css] div.contents{ background:url(‘../images/background.gif’) no-repeat 0 3px; } [/css] を [css] div.contents{ background:url(<%= asset_path ‘background.gif’ %>) no-repeat 0 3px; } [/css] のように書き換え、拡張子を.cssから.css.erbに変更する。 これでerbとして処理されるため速度が気になるが、production環境ではrake assets:precompileで予めコンパイルすることになるので気にしないでいい。

とりあえずdevelopmentで実行してみると、なぜかerbブロックが評価されない問題が発生した。 元になったcssでインデントがタブになっていたためだった。行頭にタブがあるとerbブロックは評価されない。全部のcssをemacsで開いてuntabifyしたら動いた。 さらに、cssの記法が正しくない箇所があるとassets:precompile時に例外が発生することがある。 cssは文法が正しくなくても動いてしまうので、記法ミスに気づきにくい。

developmentで動いたら今度はrake assets:precompileしてデプロイする。 おっと、deploy.rbに

set :normalize_asset_timestamps, false

を追加すること。

次にサーバ側の設定。nginxのドメインごとの設定に

location ~ ^/assets|system/ {
         expires 1y;
         add_header Cache-Control public;
         add_header Last-Modified &quot;&quot;;
         add_header ETag &quot;&quot;;
}

を追加し、reloadする。(/imagesなどが設定されていたら削除する) これで完了・・・と思いきや、なぜかnginxがエラーを返す。 今までpublic/直下に置いていたfavicon.icoが無くなったため、ブラウザが勝手に/favicon.icoを探しに行ってエラーになっているようだ。これはfavicon.icoを/app/assets/imagesに配置し、レイアウトのヘッダ部に <%= favicon_link_tag ‘favicon.ico’ %> を追加することで解決できる。

はー疲れた。

3.1+時代ではcssもそのまま配置せず、いったんエンジニアが目を通す必要がありそう。 コーディング規約をちゃんとしていれば大丈夫かな?