Wednesday, June 20, 2007

Deploying Rails applications to multiple environments

I love capistrano, however I had some trouble finding solid doc on how to deploy your app to multiple environments (UAT, staging, etc.) So here is a quick and dirty of the solution I can up with.

cap deploy

The old standby, this will configure our deployment based on deploy.rb. We want to conditionally configure our deployment so we need to pass a parameter to this comment, this is done with -S

cap deploy -S stage=uat

This sets a local variable 'stage' to 'uat' in our deploy.rb

Here is our conditional code from deploy.rb

if stage == 'production'
set :application, "foo"
set :repository, "http://svn.agiledog.com/svn/agiledog/foo/trunk"

# Without this $RAILS_ENV on the destination server will be used to determine the server environment
set :rails_env, :staging

role :web, "app.agiledog.com"
role :app, "app.agiledog.com"
role :db, "app.agiledog.com", :primary => true
elsif stage == 'uat'
# Different application names are used to allow different stages to be deployed on the same server if required
set :application, "uat-foo"
set :repository, "http://svn.agiledog.com/svn/agiledog/foo/branches/RB-4.0"
set :rails_env, :uat

role :web, "uat.agiledog.com"
role :app, "uat.agiledog.com"
role :db, "uat.agiledog.com", :primary => true
else # assume app == 'staging'
set :application, "staging-foo"
set :repository, "http://svn.agiledog.com/svn/agiledog/foo/trunk"
set :rails_env, :staging

role :web, "stage.agiledog.com"
role :app, "stage.agiledog.com"
role :db, "stage.agiledog.com", :primary => true
end

We have added two new environments, staging and uat. Both of these will need to be added to the database.yml file. We will also need to create staging.rb and uat.rb to the config/environments folder to declare any specific environment settings.

One gotcha with this solution is that you will always need to set the stage variable anytime deploy.rb is read. That is to say, even though we assume the staging enironment, the following command will fail.

cap deploy

Instead you need to use:

cap deploy -S stage=staging

No comments: