David - Musings of an SRE

Loading 'deploy/assets' in Capistrano, automatically precompiles:assets

Something that I’ve just figured out after tinkering for a couple of hours.

Hope this will save someone else some trouble.

So I’m running my own custom Capistrano script that on fresh deploy setup a symlink of database.yml on the app instance, so that you don’t need to check in your database.yml file.

So in my config/deploy.rb, I have something like:

after 'deploy:update_code', 'deploy:symlink_db', 'deploy:assets:precompile'
.
.
.
.
  desc "Symlinks the database.yml"
  task :symlink_db, :roles => :app do
    run "ln -nfs #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml"
  end

What happened is that during the first deployment, for some reason, ‘deploy:assets:precompile’ always run after the callback at ‘deploy:update_code’ is run and before ‘deploy:symlink_db’. This causes the entire deployment to fail because, there is no config/database.yml anywhere. (Remember, I haven’t checked it in and put it on ignore).

Reading the documentations, callbacks should be run in precedence and because deploy:symlink_db is placed before deploy:assets:precompile, it should have ran first.

But it didn’t.

Hmm.

Then, I decided to remove ‘deploy:assets:precompile’ and deploy.

It should skip right?

Nope.

Now what?

The next logical step is to comment the entire ‘deploy:assets:precompile’ section out. And deploy again.

It should work. Right, right?

Nope.

So I did some reading up.

Here and here.

Turns out, when you load ‘deploy/assets’, the recipe automatically adds in the precompile at the correct part of your deployment. Bleah!

Solution: uncomment load ‘deploy/assets’ and things miraculously works once again.

So, moral of the story, if you want to make sure assets:precompile don’t get run unless you explicitly tell it to, don’t load deploy/assets.

Word.

Update: So apparently there’s another way to do this, which is definitely much simpler.

Because the failure was happening at the default assets precompile stage where there isn’t a database.yml linked yet, setting a before_callback would solve the problem:

before "deploy:assets:precompile", "deploy:symlink_db"