Asset PipelineというのはRails3.1から追加された機能で、以下のような特徴を備えています。なかなか便利そうなやつです〜。
ではどういった仕組みなのか見てみましょう。
例えばRails3.2.3で新しいアプリを作成したとします。このとき、Gemfileにはデフォルトでjquery-railsが指定されています。そしてapp/assets/javascripts/application.jsはこのように書かれていると思います。
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以下も探してくれます。
そして、注目は下二つです。それぞれjquery-railsとcoffee-railsのgemを参照しています。つまり、アプリケーション内には無くてもgemの中に置かれていればそれを参照することが出来るというわけですよ。クール。
実際中身を覗いてみても、ファイルが存在していることは確認できますね :)
さらに、aseetsにはhttpベースでアクセスすることも可能です。例えば app/assets/javascripts/application.js には http://localhost:3000/assets/application.js でアクセスすることができます。
app/assets以下はどのサブディレクトリに置いたとしても同様に扱われます。
つまりこんな感じ。
application.jsを見れば難読化されていることも確認できます。知らないところでいろんなことやってくれてるんですねぇ。けなげなやつですほんまに。
# jquery.js単体 (難読化されてない)

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

--- 以下、ちょっと余談 ---
ただ、このままだとdevelopment環境であれば問題ないですが、production環境で動かそうとするとアクセスできないと言われちゃいます。ギャー。
これはprecompileしてあげることで回避できます。
もしくはconfig/environments/production.rbの以下の設定をtrueにしてリアルタイムに都度都度コンパイルするようにするか…(負荷高そう)
ただ、これでもまだエラーは出ます。production環境にしたら急にルーティングが効かなくなってassetsが見れなくなった。ヒー。
これはconfig/environments/production.rbの以下の設定をtrueにすることで回避できます。これは静的ファイルの扱いをRailsで行うかどうかっていう設定です。
ApacheやNginxを使っていればそれらが静的ファイルを返してくれてRailsではやる必要がないからfalseでいいけど、今回みたいに手元でちょろっと動かしてみるときにはこの値をtrueにするといいんですかね。
おしまい。
・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単体 (難読化されてない)

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

--- 以下、ちょっと余談 ---
ただ、このままだと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
おしまい。
