The blog of Rahoul Baruah from 3hv Ltd

What's going on?

My name is Rahoul Baruah (aka Baz) and I'm a software developer in Leeds (England).

This is a log of things I've discovered while writing software in Ruby on Rails. In other words, geek stuff.

However, I've decided to put this blog on ice - I would ask you to check out my business blog here (or subscribe here).

15 March, 2007

Deploying to a Staging Server with Capistrano

Capistrano is one of my favourite Rails features. It's vital to "agile" development - there's no point running through your iterations, making fast, small changes, if you can't easily get them into the hands of the (hopefully) paying public. (It's also a major reason I'm not too interested in deploying on IIS any more).

However, one of the things I have found is that sometimes you get stuff that runs fine on your local boxes but fails on your server (I had a weird one where Bluecloth worked fine here but not there - despite freezing all my Gems and Rails itself).

So I wanted to set up an intermediate deployment on my server.

A quick hunt found Mike Burn's article which I then adapted for my own purposes.

Firstly - created a new subdomain and database on my server - and a folder for deploying to.

Then I added a new environment file - /config/environments/staging.rb - this was a copy of development.rb but with code caching turned on.

Next, I set up a new database configuration in /config/database.yml - staging: that points to my newly created staging database.

To get Capistrano to deploy correctly, I amended /config/deploy.rb like so:

if stage == "production"
set :deploy_to, "/home/user/myapp_live"
set :deploy_to, "/home/user/myapp_staging"

I also needed to adapt things after the code had been copied, so the following was added to the end of deploy.rb:

desc "After updating the code, back up the database and migrate"
task :after_update_code do
run "/home/user/mysql/"
# if this is a staging deployment, switch the environment to staging, not production
if stage == "staging"
# switch to the staging environment
run "sed -i 's/\"production\"/\"staging\"/' #{release_path}/config/environment.rb"
# migrate the database
run "cd #{release_path} && rake RAILS_ENV=staging db:migrate"
# migrate the database
run "cd #{release_path} && rake RAILS_ENV=production db:migrate"

Basically, I did not trust the deploy_with_migrations task to work the way I wanted it to (I kept noticing rake RAILS_ENV=production db:migrate appearing in the log).

So instead I back up my database manually using a script and then - if I'm in production mode I just migrate the database (explicitly setting the Rails Environment). However, if I'm in staging mode then I use sed to change my environment settings (so that the line ENV["RAILS_ENV"] ||= "production" becomes ENV["RAILS_ENV"] ||= "staging") and then migrate the database (explicitly setting the Rails Environment).

One final step - I created two shell scripts - deploy and deploy_to_production that look like this:

# deploy
#! /bin/sh
cap -S stage=staging deploy
# deploy_to_production
#! /bin/sh
cap -S stage=production deploy

These call Capistrano's deploy task, setting an internal variable stage to "staging" or "production" respectively.

Further Enhancements - I'm going to change deploy.rb so that it uses different Subversion Urls for staging and production - so staging pulls from http://mysvn/myapp/staging and production pulls from http://mysvn/myapp/live.

No comments:

eXTReMe Tracker