Converting a Rails App to Capistrano deployment

03 Aug 2006

I’ve got one client for whom I’m building a Rails app and I started it long before I knew anything about Capistrano. Mostly things are pretty straightforward and all is working as it should - but there are a couple of hangups.

Shared Resources

My site allows users to upload portraits of themselves. These are kept right in the open in the public directory under a folder named “portraits”. They can also upload films, documents, etc. using the model Documents which stores its stuff in ./public/documents.

The first real hassle of converting to capistrano was dealing with these because up until now I’ve kept them in the SVN repository for fear of losing any data and pisisng off a user. With the number of deployments I do I no longer want to put these files in the repository but that would remove them from the site. Capistrano does a fresh checkout each time it deploys and if something’s not in SVN then it just plain doesn’t make it back into the app.

Capistrano does allow the use of a shared folder located above the live app directory. The trick is getting stuff into there and making sure that capistrano can recognize it every time I deploy.

My Solution

It turns out the Capistrano allows highly configurable deployment options. All I needed to do was to move the folders out of ./public and into shared

mv ./public/documents ../shared/
mv ./public/portraits ../shared/

then edit my deploy script so it links those folders up into each new public directory

task :after_update_code do
  %w{documents portraits}.each do |share|
    run "ln -s #{shared_path}/#{share} #{release_path}/public/#{share}"
  end
end

It didn’t take long for me to realize that I needed to do the same with any other file that wouldn’t be in SVN. For me, this is my database.yml file and cofig/environment.rb file

task :after_update_code do
  %w{documents portraits}.each do |share|
    run "ln -s #{shared_path}/#{share} #{release_path}/public/#{share}"
  end
  %w{database.yml environment.rb}.each do |config|
    run "ln -nfs #{shared_path}/#{config} #{release_path}/config/#{config}"
  end
end

There’s actually a number of tasks that you could add this code to. You could put it right into the deploy task by using task :deploy or you could make it run immediately after deploy is run by task :after_deploy

So far so good with Capistrano.


Please if you found this post helpful or have questions.