Practical eCommerce

 

Creating Symlinks When Deploying a Rails Application

 
avatar

One of the really cool parts of deploying a Rails application is using Capistrano to make it easy. I still sit and revel in the simplicity each time I deploy changes to a Rails application. However, I'll be the first to admit that the key to happy deployment lies in a good deployment recipe. Without one, deployment can be a frustrating and extremely annoying process. Case in point, have you ever deployed changes to your Rails application only to find that all the images uploaded through you website have disappeared, hidden away in a previous "version" of your application?

The Problem

We'll take a look at how to fix that problem by using the shared directory on your server and taking advantage of symbolic links, or symlinks. But first, let's explain why deploying with Capistrano can cause these problems.

When you use Capistrano to deploy your Rails application, your first go through the process of setting up your server, hopefully by using the cap deploy:setup task. Running this will cause Capistrano to create a couple of directories on your web server called current, releases and shared. The following explains how each of these directories is used:

Symbolic Links

As you may have guessed, I'm going to discuss how to use symbolic links in your deployment recipe in order to preserve content between deployments. In our example a website allows people to upload images for display on the site. However, we want to avoid having these images stored in the current directory so that they are not moved to the releases when the Rails application is deployed.

First of all, let's assume that our images are being uploaded to a directory called uploads, located in the public directory of our Rails application. The first step in our process is to remove that directory from our repository (or set the Subversion ignore settings) to ensure that the directory is not being contained in our Rails application.

So now that we have removed that directory, we need somewhere to upload files to. In addition, our application is already set up to use the uploads directory and we shouldn't have to go through and change any of that. We will create an uploads directory on our web server inside of the shared directory, perhaps even inside the system directory just to keep things all together. Make sure to set the permissions so that files can be written to that directory by the application.

We now have a place for the files to be uploaded that will not be affected by deployments. The only thing that we need to do next is to use a symlink, or symbolic link, to tell the web server that links to the public/uploads directory inside the current Rails application should actually lead to the uploads directory inside the shared folder, which is not affected by deployments. It's like saying to the web server "treat this shared uploads folder as though it is the public uploads folder of the most current Rails app version."

We create this symbolic link by running the following command on our web server:

ln -nfs shared/system/uploads current/public/uploads

If you check your application, you will see that the uploaded image files are now being stored in the shared uploads directory. However, this will require us to log in to our web server after each deployment and create this symlink, which is annoying. Luckily, we can create a Capistrano deployment recipe that automates this task.

The Deployment Recipe

Rather than having to manually create our symlinks, let's take a look at how to create a custom deployment task that will be run whenever we deploy our Rails application.

This is a great time to mention that that config/database.yml file is a wonderful candidate for storing in the shared directory and symlinking to it. By doing this, you can avoid having to publish your development and testing passwords, and multiple developers can easily collaborate on the same project.

Let's get started by opening up the config/deploy.rb file that contains our deployment recipe. Since our application is already up and running, we will only be adding some things to the end of the recipe that is currently in place for your web host. In this example we create a namespace called "customs" for our new tasks:

namespace(:customs) do
  task :config, :roles => :app do
    run <<-CMD
      ln -nfs #{shared_path}/system/database.yml #{release_path}/config/database.yml
    CMD
  end
  task :symlink, :roles => :app do
    run <<-CMD
      ln -nfs #{shared_path}/system/uploads #{release_path}/public/uploads
    CMD
  end
end

As you can see, we have defined two custom tasks, one called config and one called symlink. They both create symlinks, with the first creating a symlink for our database.yml file, and the second creating a symlink for our uploads directory. You might have noticed that Capistrano gives us a couple of variables to work with:

In order to get Capistrano to perform these tasks each time we deploy our application, we need to set some hooks by placing the following code at the bottom of our deploy.rb file:

after "deploy:update_code", "customs:config"
after "deploy:symlink","customs:symlink"
after "deploy", "deploy:cleanup"

The first line tells Capistrano that after it has performed the update_code methods, which updates the Rails application, that it should symlink to our shared database.yml file so that Rails has the production database configuration settings.

The next line tells Capistrano that once it has finished symlinking the application (a normal deploy involves symlinking to the current directory), it should then create the symlink for our uploads directory.

Finally, I have added a third line that tells Capistrano to finish it all up by running the cap deploy:cleanup task, which removes all but the last 5 releases from the releases directory. We do this for good housekeeping reasons so that we are not bloating our server with releases that we don't need.

And with that, we have successfully created symbolic links that will allow us to define parts of our application that are shared among all releases, and independent of the deployment process.

This post is filed under Developers' Corner and has the following keyword tags: ruby, rails, capistrano, deployment, symlink.

0 Comments

Sign-up to receive EcommerceNotes, our acclaimed email newsletter.

Bloggers Wanted

We’re looking for merchants and other ecommerce professionals to share their experiences with our readers. If this interests you, we invite you to contact us.

Help

Featured Tags | All A-Z

 

Inside Practical eCommerce