Asset PipelineというのはRails3.1から追加された機能で、以下のような特徴を備えています。なかなか便利そうなやつです〜。

・cssやjsは各々一つのファイルにまとめられる(ブラウザのリクエスト回数を減らせる)
・それらのファイルは自動で圧縮/難読化される(ファイルサイズを減らして負荷軽減)
・ついでに、SassやCoffeeScriptを使ってcssやjsを記述することが可能になっている

ではどういった仕組みなのか見てみましょう。

例えばRails3.2.3で新しいアプリを作成したとします。このとき、Gemfileにはデフォルトでjquery-railsが指定されています。そしてapp/assets/javascripts/application.jsはこのように書かれていると思います。

//= require jquery
//= require jquery_ujs
//= require_tree .

application.jsではいろんなjsをrequireしていますが、ここで指定したファイルの中身が展開されて一つにまとめられてapplication.jsとなります。そのため、Rails側ではこのapplication.jsを読み込むだけでjqueryやjquery_ujsの機能が利用できるようになるわけです。

では、これらのファイル (jquery.js, jquery_ujs.js) はいったいどこに存在しているのでしょう、、?public以下には存在していないようですががが。。

実はAsset Pipelineのロードパスを見てみるとわかるんですが、app/assets以下だけでなく、lib/assetsやvendor/assets以下も探してくれます。

> y Rails.application.config.assets.paths
---
- /Users/sasata299/sample/app/assets/images
- /Users/sasata299/sample/app/assets/javascripts
- /Users/sasata299/sample/app/assets/stylesheets
- /Users/sasata299/sample/lib/assets/javascripts
- /Users/sasata299/sample/lib/assets/stylesheets
- /Users/sasata299/sample/vendor/assets/javascripts
- /Users/sasata299/sample/vendor/assets/stylesheets
- /Users/sasata299/.rvm/gems/ruby-1.9.3-head/gems/jquery-rails-2.1.3/vendor/assets/javascripts
- /Users/sasata299/.rvm/gems/ruby-1.9.3-head/gems/coffee-rails-3.2.2/lib/assets/javascripts

そして、注目は下二つです。それぞれjquery-railsとcoffee-railsのgemを参照しています。つまり、アプリケーション内には無くてもgemの中に置かれていればそれを参照することが出来るというわけですよ。クール。

実際中身を覗いてみても、ファイルが存在していることは確認できますね :)

$ ls -l /Users/sasata299/.rvm/gems/ruby-1.9.3-head/gems/jquery-rails-2.1.3/vendor/assets/javascripts/
total 1872
-rw-r--r--  1 sasata299  staff  365231 10 26 19:20 jquery-ui.js
-rw-r--r--  1 sasata299  staff  200748 10 26 19:20 jquery-ui.min.js
-rw-r--r--  1 sasata299  staff  266882 10 26 19:20 jquery.js
-rw-r--r--  1 sasata299  staff   93436 10 26 19:20 jquery.min.js
-rw-r--r--  1 sasata299  staff   17894 10 26 19:20 jquery_ujs.js

さらに、aseetsにはhttpベースでアクセスすることも可能です。例えば app/assets/javascripts/application.js には http://localhost:3000/assets/application.js でアクセスすることができます。
app/assets以下はどのサブディレクトリに置いたとしても同様に扱われます。

つまりこんな感じ。

app/assets/dir1/hoge.js #=> http://localhost:3000/assets/hoge.js
app/assets/dir2/foo.css #=> http://localhost:3000/assets/foo.css

application.jsを見れば難読化されていることも確認できます。知らないところでいろんなことやってくれてるんですねぇ。けなげなやつですほんまに。

# jquery.js単体 (難読化されてない)
jquery

# 各jsファイルがまとめられたapplication.js (難読化されてる)
application

--- 以下、ちょっと余談 ---

ただ、このままだとdevelopment環境であれば問題ないですが、production環境で動かそうとするとアクセスできないと言われちゃいます。ギャー。

$ rails s -e production

ActionView::Template::Error (application.css isn't precompiled):

これはprecompileしてあげることで回避できます。

bundle exec rake assets:precompile RAILS_ENV=production

もしくはconfig/environments/production.rbの以下の設定をtrueにしてリアルタイムに都度都度コンパイルするようにするか…(負荷高そう)

# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = true

ただ、これでもまだエラーは出ます。production環境にしたら急にルーティングが効かなくなってassetsが見れなくなった。ヒー。

ActionController::RoutingError (No route matches [GET] "/assets/application-7270767b2a9e9fff880aa5de378ca791.css"):

これはconfig/environments/production.rbの以下の設定をtrueにすることで回避できます。これは静的ファイルの扱いをRailsで行うかどうかっていう設定です。

ApacheやNginxを使っていればそれらが静的ファイルを返してくれてRailsではやる必要がないからfalseでいいけど、今回みたいに手元でちょろっと動かしてみるときにはこの値をtrueにするといいんですかね。

# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = true

おしまい。
このエントリーをはてなブックマークに追加