前回の記事で書いたとおりRailsの環境を更新しました。
が、本番環境おけるアセットパイプラインでハマってしまいました。
ここで復習しておきます。
そもそもアセットパイプラインとは?
「app/assets」「lib/assets」「vendor/assets」など異なるパス上のjsやcssを同一のurl(例えばhttp://myapp:3000/assets/xxxx)で参照を可能にする仕組みです。(jsやcssの結合だったり圧縮だったり他にも色々仕事してます。)
アセットパイプラインの対象となるパスは「Rails.application.assets.paths」で参照できます。
#/myappが$RAILS_ROOT $ script/rails console irb(main):001:0> puts Rails.application.assets.paths /myapp/app/assets/images /myapp/app/assets/javascripts /myapp/app/assets/stylesheets /myapp//vendor/assets/javascripts /myapp/vendor/assets/stylesheets /myapp/vendor/bundle/ruby/2.1.0/gems/jquery-rails-3.1.0/vendor/assets/javascripts /myapp/vendor/bundle/ruby/2.1.0/gems/coffee-rails-4.0.1/lib/assets/javascripts
アセットパイプライン(Asset Pipeline) - - Railsドキュメント
5分でわかる!? アセットパイプライン(Assets Pipeline) - Rails つまみぐい
RailsのAsset Pipelineの理解とgemで管理しないJavaScriptライブラリの配置 | EasyRamble
#279 Understanding the Asset Pipeline - RailsCasts
production環境におけるアセットパイプライン
このアセットパイプライン、production環境では「コンパイル済みのファイルを探す」という動きをとります。
つまりデプロイ前にコンパイルしないと、アセットパイプライン上に配置したファイルが404エラーとなってしまいます。
解決策
1. 手動でプリコンパイルする
rakeタスクでアセットファイルをプリコンパイルしておくことができます。
$ bundle exec rake assets:precompile RAILS_ENV=production
そうすると$RAILS_ROOT/public/assetsの中にプリコンパイルされたファイルができあがります。
が、この方法は当然ながらプリコンパイルしたファイルをリポジトリに登録する必要がありちょっとイマイチかも。
そこで、
2.動的にコンパイルする
サーバがリクエストを受け取った際、コンパイル済みのファイルが見つからない場合にその場でコンパイルを行う設定が可能です。
設定は$RAILS_ROOT/config/environments/production.rbで行います。
#config/environments/production.rb # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = true #trueに設定すると動的コンパイルが「有効」
これならリポジトリへの登録は不要です。しかし動的コンパイルなので初回リクエスト時にはレスポンスが犠牲になります。
それが嫌なら、
3.デプロイ時にプリコンパイルをする
capistrano-railsを利用することでcapistranoによるデプロイ時、デプロイ先にプリコンパイルしたアセットファイルを作成することができます。
Gemfileに定義して
#Gemfile … gem 'capistrano-rails'
インストールして
$ bundle install
Capfileで読み込めばOK。
#Capfile … require 'capistrano/rails/assets'
これでデプロイ先の$RAILS_ROOT/current/public/assetsにコンパイル済みのファイルが配置されます。
されるはずだったが・・・
上記のCapistranoによるプリコンパイルを実施したのですが、上手くいきませんでした。
こんなエラーが出たのです。
Started GET "/assets/first.png" for 106.188.44.126 at 2014-06-27 00:51:18 +0900 ActionController::RoutingError (No route matches [GET] "/assets/first.png"):
上記のfirst.pngは$RAILS_ROOT/app/assets/imagesに格納しています。
アセットパイプライン上に置いているし、プリコンパイルもしたのにファイルが見つからない?
このエラーの原因は直接パスを指定していることにありました。
上記の画像はviewの中で直接パスを指定していました。
<img serc="assets/first.png" />
developmentならば特に問題ありませんが、production環境ではこれをpublic/assetsに置く必要があります。
そこでプリコンパイルを実施するわけですが、Rails4からはプリコンパイルの成果物がRails3の頃と変更になってます。
上記first.pngを例に取ると、Rails3の頃は
public/assets/first.png public/assets/first-xxxxx.png #xxxxxはハッシュ値
と元のファイル名そのままのものとハッシュ値が付いたファイルが生成されていたのに対し、Rails4では
public/assets/first-xxxxx.png #xxxxxはハッシュ値
とハッシュ値付きのものしか生成されません。
そのため直接パスを指定していると書いてある通りのファイル名がリクエストされ、404となります。
これに対する解決方法はasset_pathメソッドを利用することです。
<img src="<%= asset_path 'first.png' %>" />
asset_pathにアセットパイプライン上のファイル名を指定するだけで、development、productionそれぞれに適した形に変換してくれます。
#development <img src="/assets/first.png" />
#production <img src="/assets/first-696d2d60937a6e31851de94c4e646e3b.png" />
Rails4ではbackground:url("assets/hoge.png")の書き方は動かない話
asset_path - リファレンス - - Railsドキュメント
Railsのasset_pathは何をやってくれてるのか - (゚∀゚)o彡 sasata299's blog
これで解決!と思っていたら別の問題が起きていました。
Started GET "/index.css" for 127.0.0.1 at 2014-06-28 18:11:40 +0900 ActionController::RoutingError (No route matches [GET] "/index.css"):
index.cssはトップページでのみ使いたいため、application.cssではrequireせずvendor/assets/stylesheetsに置いています。
しかリクエストされたファイル名を見ると、ハッシュ値なしのファイル名が・・・
app/public/assets内を確認すると、このcssはプリコンパイルされていませんでした。
原因はRails4でのassets:precompileにおけるコンパイル対象にありました。
Rails4ではアセットファイルのプリコンパイル対象が以下のように定義されています。
@assets.precompile = [ Proc.new { |path, fn| fn =~ /app\/assets/ && !%w(.js .css).include?(File.extname(path)) }, /(?:\/|\\|\A)application\.(css|js)$/ ]
読み解くと
がプリコンパイルの対象となります。
つまり、アセットパイプライン上のファイル≠プリコンパイル対象ってことなの!
じゃあどうすればいいのか。application.cssに含めるしかないのか?
コンパイル対象を増やしたい場合はconfig/application.rb内で設定することが可能です。
#config/application.rb config.assets.precompile += %w(index.css)
Rails4でGemの資産がAssets Precomplieに含まれないときは · THINKING MEGANE
これで全て解決しました。
でもこの方法だとapplication.js|cssでrequireしないファイルが増えるたびに設定を追加しないといけなくて微妙だなー、とも思います。
うーん、Rails難しい!
Ruby on Rails 4 アプリケーションプログラミング
- 作者: 山田祥寛
- 出版社/メーカー: 技術評論社
- 発売日: 2014/04/11
- メディア: 大型本
- この商品を含むブログ (6件) を見る
実践Ruby on Rails 4 現場のプロから学ぶ本格Webプログラミング
- 作者: 黒田努
- 出版社/メーカー: インプレス
- 発売日: 2014/05/23
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る
- 作者: 高橋征義,後藤裕蔵,まつもとゆきひろ
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2013/06/04
- メディア: 単行本
- この商品を含むブログ (33件) を見る