サーバ側でassets:precompileしたくない

こんばんは.
インターン生にプログラムを教えている風な投稿をさせておきながら,実情はアニメを勧めているだけです,@h3_potetoです.



RailsにAsset-Pipelineが導入されて久しいですね.
3.2以降から導入されていたと思うので,このあたりを見ると詳しく乗っているかと思います.
http://ja.asciicasts.com/episodes/279-understanding-the-asset-pipeline


さて,
asset関連を使っていると,developmentではさして問題ないけどproductionでは……ということがたまにあります.
特にcompile関連はよくできていて,


production.rb

config.assets.compile = true

としておくと,なんとproduction環境にもかかわらずasset関連のファイルを動的にコンパイルしてくれる.
はっきり言って重い.

こうしたくないからこそ

production.rb

config.assets.compile = false

config.assets.precompile += %w( *.js *.css *.less *.erb )

としていたりします.
ってことは自動的にproductionで動かすときにはprecompileが必須になってくるわけですね.

そのために用意されているのが

$ rake assets:precompile

これをやると,public/assets/以下にプリコンパイル済みのassetsを生成してくれる.
でもこれらのファイル,基本的にはコミットには含めない.


そのため,デプロイする際にはどこかでプリコンパイルしてやる必要があります.



asset_syncを使うことも多い


さらに,asset関連のファイルをpublicに置くというのは大きなアプリになればなるほど嬉しくない.
ましてやロードバランサーを挟んで,複数インスタンスを起動するようなサーバ構成をする場合は,できればそんなことはやりたくない.

そこで,assetのみを別のサーバに格納しておき,すべてそこから読み込むという方法がある.

https://github.com/rumblelabs/asset_sync


これにより,プリコンパイルされたファイルはすべてasset用のサーバにアップロードされます.
そして,asset_hostによりそのサーバを指定してやれば,assetはすべてそのサーバから読み込まれます.


なんというスマートさ.



でも,いちいちデプロイするたびにプリコンパイルするのめんどくさい


そこで登場してくるのが,manifestファイルというものです.


プリコンパイルで生成されるassetはすべてMD5によって謎のハッシュ値が付いている.
これにより古いファルが読み込まれることがないのだが,直前のプリコンパイルで作ったファイルはどれ?という問題は残る.
それらの情報を記述しておくのがmanifest.



つまり,precompileは開発側でやっておいても,manifestファイルさえあれば問題なく,希望するassetを読み込んでくれる.

production.rb

config.assets.manifest = File.join(Rails.root, "public", "assets")


asset_sync.rb

config.manifest = true

としてやれば無事,manifestファイルを読み込んでくれます.
あとは,manifestファイルだけをgit管理下にしておけば大丈夫ですね.




開発の手順としては,

①app/assets/以下のファイルに変更を加える
②assets:precompileを実行
③manifestファイルが更新されたことを確認しコミット
④デプロイ


という手順になります.
もちろんprecompileは事前に行っているのでサーバ側でassets:precompileを実行する必要はなくなります.





そもそも,サーバを複数台用意してロードバランサーを挟んだ段階で,各インスタンスでプリコンパイルするという選択肢はナンセンスなので,できればどこもこういう実装にしておきたいですね.