development環境下でprecompileすると,以降developmentでassetsが上手く読み込まれない
寒くなったら鼻の調子が最悪になりました,@h3_potetoです.
息をするのがつらい.
今日はRailsのasset関連の話をちょとします.
RailsにはAsset Pipelineという機能があります.
これが非常に便利な話は以前したことがあったかと思います.
このassets,実際にproduction環境下で動かすためにはprecompileをするのが一般的です.
たとえば,
config/environments/production.rb
config.assets.compile = false config.assets.precompile += %w(*.js *.less *.css *.erb)
というような設定をしておくことで,production環境で動くrailsがassets以下のフォルダから動的にコンパイルするのを防ぎ,予めprecompileしておいたassetsのみを参照することができます.
precompileをローカルで行うとおかしい
普通に運用する限り,precompileしたassetsはproductionで動かすときにだけ存在すれば良いはずです.
しかし様々な事情(※後述)により,どうしてもローカルでprecompileしなければならないときがあります.
そうしてprecompileするのですが,一度precompileしてしまうと,developmentでアプリケーションを起動しても,precompile時に生成されたmanifestの値をassetsとして読み込んでしまうことが,たまにあります.
とりあえず試しにassets:clean
$ bundle exec rake assets:clean
rails4.0以降ではassets:clobber
という名前に変更されています.
ただ,これだと特になんの変化も起きません.
生成されたmanifestファイルを削除しても変化なし.
キャッシュを消してみる
これはcache_stroeに何を使っているかにもよりますが,一度キャッシュを消してみましょう.
tmp/cache/assets
に大量にファイルができていると思うので,潔く消しましょう.
で,ここまで来てもダメなことがあります.
というか,たいていこの状況になったらこれらの手段では改善しません.
gitの差分を見てみても,特になにか設定が変更されているということはないと思います.
developmentの設定をいじる
一時的にdevelopmentの設定を変更します.
おそらく
config/environments/development.rb
config.assets.debug = true
となっているので,
config.assets.debug = false
に変更します.
もともとのこ設定は,application.css等で読み込んでいる外部ファイル(scssなど)を,個別に読込し直すかどうかの設定になります.
これをtrueにしているため,development環境下では,個々のscssファイルやcoffeeファイルを読み込んでいて,ブラウザ側からファイル別にたどることができます.
precompileをすると,これら個別のファイルがすべてapplication.css等に統合され,各サイトではapplication.cssしか読み込まなくなっているかと思います.
この設定を一度変更してやることで,development環境でのassets読み込みが正常に戻ります.
一度成功したら,assets.debugの設定は元に戻しても大丈夫です.
ローカルでprecompileしたい理由
Railsアプリケーションを単一のサーバーで動作させている限り,さほど大きな問題はありません.
しかし,複数台のサーバーでバランシングして運用する場合,個々のサーバーのpublicフォルダ内にprecompileしたassetsを格納しておくのは,あまり賢い手段とは言い難いです.
そのため,インターファームではAWS S3にprecompileしたassetsファイル群を格納し,それをcloudfrontを通してキャッシュして読み込むという手法を取っています.
これを実現するために,asset_sync(https://github.com/rumblelabs/asset_sync)とaws-sdkを使って,precompileと同時にpublicフォルダ以下に作成されたassetsファイル群をS3にアップロードしています.
そして,manifestファイルのみをコミット対象として,本番にデプロイすることで,最新のprecompileによって生成されたassetsが読み込まれるようになります.
このprecompile,サーバー側で行ってもいいのですが,deployタスクに積むと
・デプロイが重くなる
・複数台構成のサーバーで各々がprecompileすると,同じassetsが二重にS3にアップロードされて冗長
という問題が発生します.
となると,ローカルでprecompileしておいて(asset_syncされる),manifestファイルのみをコミットしてpushするというのが望ましい.
だからこそローカルでprecompileが必要になってきます.