目的
通常、
rake assets:precompile
でアセットをコンパイルするとpublic/assetsディレクトリにapplication-9ac74f0fddf98cc98595755d9e0c96aa.cssの様なファイル名のファイルが生成されます。
これはとても便利なんですが、場合によってはダイジェスト値を含まないapplication.cssというファイルを生成して欲しいことが有ります。
(理由は後述します)
方法
これを実現するにはlib/tasks/assets.rakeなどのファイルを作り、以下の内容で保存します。
namespace :assets do
def without_digest
Sprockets::Asset.class_eval do
def hacked_digest_path
logical_path
end
alias_method :org_digest_path, :digest_path
alias_method :digest_path, :hacked_digest_path
end
yield
Sprockets::Asset.class_eval do
alias_method :digest_path, :org_digest_path
end
end
task :precompile_without_digest => :environment do
without_digest do
Rake::Task["assets:precompile"].invoke
end
end
end
これで
rake assets:precompile_without_digest
を実行するとダイジェスト値の無いアセットが生成されます。
あとは、**stylesheet_link_tag
**などのメソッドがダイジェスト無しのファイル名を返すように、config/environments/xxxxx.rbの設定を以下の様に変更します。(xxxxxは適宜、環境に応じて読み替えて下さい)
config.assets.digest = false
そもそもなぜダイジェスト値の無いアセットが欲しいのか
ダイジェスト値を持つアセットを生成することのメリットは以下です。
- アセットのブラウザキャッシュ有効期限を遠い未来にすることでサーバへのアセットリクエスト数を激減させることが出来る。
- アセットに変更が有った場合には**
stylesheet_link_tag
**などのメソッドは新しいダイジェストを持つファイル名を返すので、ブラウザは確実に新しいアセットを取得しに行く。
ただし、これが機能するのは常にページが動的に生成されている場合に限られます。
サーバ負荷を下げる目的で、actionpack-page_cachingやNginxのキャッシュ機能を使用していた場合には、アセットを更新してもページキャッシュが残っている間はブラウザは古いアセットを取得し続けます。
新しいアセットをブラウザに読み込ませるにはページキャッシュを消すなり、更新する必要があります。
そこで、登場するのがダイジェスト無しのアセットです。
コレには以下のメリットが有ります。
- アセットを更新してもページキャッシュには何もしなくていい。
同時に以下のデメリットも有ります。
- アセットはブラウザキャッシュさせられない。
結局、どちらがいいかは、
- ページキャッシュによる負荷削減
- アセットがブラウザキャッシュされないことによる負荷増加
のトレードオフを考慮してどちらが得かによって決まると思います。
余談ですが、もう一つの選択肢として、ダイジェスト付きアセットを使いつつ、アセットの更新時にページキャッシュを再生成するという方法もあります。
これが実装は面倒ですが一番負荷を下げられる方法ですね。(ページをブラウザキャッシュさせてる場合は意味無いですが)