There's an echo in my head

日々のメモ。

capistranoでassetsに更新がない場合にprecompileを行わない

サーバ間に差異があると意図どおりに動かない可能性があるのでおすすめできない(追記2参照)

capistranoのでデプロイをするとdeploy:assets:precompileを走らせてassetsのコンパイルをしてくれるけど、毎回assetsに変更があるわけではない。なので変更がない場合にはprecompileを行わないように手を加える。

config/deploy/assets.rb:

namespace :deploy do
  namespace :assets do
    desc <<-DESC
      Run the asset precompilation rake task. You can specify the full path \
      to the rake executable by setting the rake variable. You can also \
      specify additional environment variables to pass to rake via the \
      asset_env variable. The defaults are:

        set :rake,      "rake"
        set :rails_env, "production"
        set :asset_env, "RAILS_GROUPS=assets"

      If no changes are found in app/assets, vendor/assets, and Gemfile.lock,
      the precompilation will be skipped.
    DESC
    task :precompile, :roles => lambda { assets_role }, :except => { :no_release => true } do
      begin
        from = source.next_revision(current_revision)
      rescue
        # Fail at first-time deploy because of current/REVISION absence
        err_no = true
      end
      if err_no || capture("cd #{latest_release} && #{source.local.log(from)} vendor/assets/ app/assets/ Gemfile.lock | wc -l").to_i > 0
        do_precompile
      else
        logger.info "Skipping asset pre-compilation because there were no asset changes"
      end
    end
    desc <<-DESC
      [internal] This task is a copy of original deploy:assets:precompile.
    DESC
    task :do_precompile, :roles => lambda { assets_role }, :except => { :no_release => true } do
      # オリジナルのdeploy:assets:precompile の内容を持ってくる
      # https://github.com/capistrano/capistrano/blob/master/lib/capistrano/recipes/deploy/assets.rb#L61
    end
  end
end

config/deploy.rb:

load "config/deploy/assets.rb"

これでapp/assetsvendor/assetsGemfile.lockに変更がある場合にだけprecompileを行なってくれる。Gemfile.lockも見ているのは、gemによってはassetsを提供するものがあるから。

ちなみにいくつか同じ意図のコードを見たけど、どれもprecompileを実行する=rake assets:precompileを実行するとなっているところばかりだった。けど、capistranodeploy:assets:precompileはmanifestファイルのコピーなどもやっているみたいなので、ここでは元々のタスクをdo_precompileとして利用している。*1

参考

追記

remote_cacheしている場合には使えないとのこと。

追記2

captureは一つのサーバ*2にしか確認しに行かないので、あとからサーバを追加した場合にそれだけprecompileされないということが発生する。

記述ルールを作ればいいのかもしれないけど、忘れられる可能性があるのでおすすめできない。

*1:タスクのリネームができるともっとわかりやすい&後々の変更が少なくてすむんだけどなぁ。

*2:列挙された最初のサーバ?

このブログに出てくるコードスニペッツは、引用あるいは断りがない限りMITライセンスです。