Deploying ColdFusion Apps With Capistrano Part 3

Hopefully by now you have had a chance to play around with Capistrano and had a chance to deploy one of your apps. If you have and your anything like me, Im sure you ran into a situation where you needed to have a bit more flexibility in your deployment. Since most of the apps I deploy are written using the ColdFusion on Wheels framework, there are a few files that I dont want to deploy to production. So using that as an example, Im going to walk you through setting up and using shared files in your deployments.

Lets use our environment.cfm file as our example. This file simply tells our application what mode it should be running in. On my local workstation, Im typically running in design mode so all of my debugging info is displayed and nothing is cached. But when I deploy that to production, I dont want to push that file up with a value of ‘design‘ setting the environment, I want to keep it in ‘production‘ mode. So lets looks at how we accomplish this.

Remember our directory structure on the server after deployments looks like this:

/site
    releases/
    shared/

So inside our shared directory, lets create a directory called config.

Now that we have a place to hold our config file, we need to copy our config to the server and make sure its set to production mode. I’ll leave that method up to you since everyones method might be different. I simply used FTP to copy my file up and then used VIM to alter the file and change it to put the application in production mode.

Now I have a path like this shared/config/environment.cfm that will match the location of the config file in my application. Thats pretty much all you have to do on the server to set this up. So now lets see how Capistrano can link to that config each time it deploys a new copy of our application.

Here is what our deploy task looked like after part 2:

# this tells capistrano what to do when you deploy
namespace :deploy do

  desc <<-DESC
  A macro-task that updates the code and fixes the symlink.
  DESC
  task :default do
    transaction do
      update_code
      symlink
    end
  end

  task :update_code, :except => { :no_release => true } do
    on_rollback { run "rm -rf #{release_path}; true" }
    strategy.deploy!
  end

  task :after_deploy do
    cleanup
  end
end

Notice all the sections that are prefixed with task? Those blocks of code actually tell Capistrano what to do during deployment. The very first one is default and is run first by Capistrano when you tell it to deploy. Inside the transaction you can see the list of tasks its going to run and each of those tasks relates to a method defined in that namespace block. So in order to tell Capistrano to link our freshly deployed copy to the shared config file we just created on our server, we need to create a new task and tell the default target to run it during deployment. Here is an updated look at the recipe with our new symlink_shared task added to it.

# this tells capistrano what to do when you deploy
namespace :deploy do

  desc <<-DESC
  A macro-task that updates the code and fixes the symlink.
  DESC
  task :default do
    transaction do
      update_code
      symlink
      symlink_shared
    end
  end

  task :update_code, :except => { :no_release => true } do
    on_rollback { run "rm -rf #{release_path}; true" }
    strategy.deploy!
  end

  desc "Symlink shared configs and folders on each release."
  task :symlink_shared do
    run "ln -nfs #{shared_path}/config/environment.cfm #{release_path}/config/environment.cfm"
  end

  task :after_deploy do
    cleanup
  end
end

All we are telling Capistrano to do is run a command on the server to create a symlink in our release path pointing to our shared/config/environment.cfm file. In order for that to run, notice we added the symlink_shared target to the default deploy task at the end of the transaction list since we want to do that last. Dont let the existing symlink task in the transaction throw you off, thats a built in task that tells Capistrano to symlink your new release version to current like we saw in part 2.

Now all you have to do is redeploy your app and your all set. No more having to worry about accidentally setting your application to the wrong environment.

There are all sorts of things you can do like this in your deployments. I have linked to shared assets directories, uploaded files directories, all kinds of stuff. Its just a clean way to deploy and have each release point to something on the server that will not change.

If you have any questions regarding this type of deployment, feel free to post a comment and I will do anything I can to help you out.

Deploying ColdFusion Apps With Capistrano Part 2

In my last post, I covered the basics of what we are trying to accomplish and some basic requirements and setup. Hopefully by now, even you Windows users have Ruby installed and the needed gems, because the fun stuff is about to begin.

The project Im deploying uses Git for SCM and lives on GitHub so Im going to focus on that as the repository to pull releases from. You can just as easily use SVN if you want with a minor tweak to your Capistrano deploy config.

Configuring Your Site

This is where all the configuration happens. Although for a basic deployment, there isnt alot of configuration. First off, you have to create your config files. Fortunately, Capistrano will do that for us. Change directory into the root or your application and type:

$ capify .

This will create a directory and two files, /Capfile, /config/, and /config/deploy.rb. These are really the only config files needed for deployment but we have to tweak them a bit since we arent using Rails.
Open up Capfile in your favorite text editor and replace its contents with the following:

require 'rubygems'
require 'railsless-deploy'
load 'config/deploy' if respond_to?(:namespace)

This basically just tells Capistrano to use the railsless-deploy gem that we installed earlier for deployments as well as tell it where our deploy.rb (recipe) is located. Its common for the /config/deploy.rb file to be referred to as a recipe so those will be used interchangeably.

Next, open the config/deploy.rb file and set it up like this example:

#replace with your servers information
set :domain, "mydomain.com"
set :user, "sshuser"

# this name should be the same as the deployment directory on the server
set :application, "site"

set :scm, :git
set :branch, "master"

# specify a hosted repository
set :repository,  "git@github.com:githubusername/myproject.git"

# or you can use the path to your local repository
#set :repository,  "file://#{File.expand_path('.')}"

server "#{domain}", :app, :web, :db, :primary => true

set :deploy_via, :copy
set :copy_exclude, [".git", ".DS_Store"]

# set this to the deployment path on your server
set :deploy_to, "/home/#{user}/public_html/#{application}"

set :keep_releases, 3
set :git_shallow_clone, 1

ssh_options[:paranoid] = false
ssh_options[:forward_agent] = true
set :use_sudo, false

# this tells capistrano what to do when you deploy
namespace :deploy do

  desc <<-DESC
  A macro-task that updates the code and fixes the symlink.
  DESC
  task :default do
    transaction do
      update_code
      symlink
    end
  end

  task :update_code, :except => { :no_release => true } do
    on_rollback { run "rm -rf #{release_path}; true" }
    strategy.deploy!
  end

  task :after_deploy do
    cleanup
  end
end

As you can see, there are several options available for deployment and you can alter the recipe to use SVN if you need, etc. The Capistrano wiki has some great documentation on all of the options available to you.

Server Setup

Now that you have your application ready to deploy, we need to tackle a couple small tasks on the server to get it ready to have our app deployed to it. Again, Im deploying to an Ubuntu server so I will be showing you the commandline way of doing it.

SSH onto your server and make sure that the deployment path that you set in your recipe exists:

$ mkdir /home/user/public_html/site

Now, on your workstation, you can allow Capistrano to setup the directory structure it uses for deployments. While still in the root directory of your site, simply type:

$ cap deploy:setup

Capistrano will go to work on your server for you and run several tasks. Primarily what you should take note of is the directory structure it creates for you. It will look like this:

site/
    releases/
    shared/

What this does is allows Capistrano to keep the number of releases you specified in your recipe in the releases directory so you can easily roll them back if need be. The shared directory is used for holding files that do not change from deployments such as uploaded images or config files. I use it to store my environment.cfm config for my CFWheels applications so when I deploy, it always points to the production environment.

Once that is done, your ready to deploy your application. On your workstation, type the following command:

$ cap deploy

This will grab the latest copy of your application from your SCM repository and deploy it to the releases directory. The other thing it does is create a symlink on your server called current/. This symlink is recreated each time you deploy your site to point to the latest released copy under the releases directory.

You have one more task on the server that has to be done in order for this to all come together. If your website root path is pointing to /home/user/public_html or something similar, you will need to repoint this to your current symlink, /home/user/public_html/site/current. This sets the doc root for your application and your site should be up and running.

After making some changes to your site and your ready to deploy the latest version, simply type cap deploy in your site root again and Capistrano will create a new folder under releases and push the latest code there. Then it recreates the current symlink and your site will be up and running the latest version. How simple is that?

Somethings Wrong, I Need to Rollback!

So in your last release you found a problem in your application, no problem. You can instantly rollback your server to the previous version by simply typing the following command on your workstation inside your applications root folder:

$ cap deploy:rollback

This will completely remove the failed last release and repoint the symlink to the previous release.

Whats Next?

If your running a simple web app or site, this should probably suffice for most of your needs. But for something that involves a little more configuration, etc. I will be doing a 3rd part to this post soon that will cover creating additional deployment tasks in your recipe to handle things like creating symlinks to shared config files, cleanup tasks and all sorts of goodies.

Stay tuned…

Deploying ColdFusion Apps With Capistrano Part 1

I love developing in ColdFusion, but one of the reasons I spend time learning other languages/frameworks is so I can get a feel for what things others are doing that could help make our jobs a little easier. Lets face it, the ColdFusion community is a little slow to progress sometimes and there is alot of innovation happening in other communities.

One of those areas is application deployment. There have been a few attempts in the past using Ant to help automate deployment. I even wrote a CF based deployment tool that used Ant under the covers and would auto-version and tag your builds and push them to your deployment servers from SVN about 5 years ago. All of the Ant based solutions have had their strengths and weaknesses and are certainly better than FTP’ing to your server and pushing files. However, after working on a few Ruby on Rails projects, I knew there had to be a better way.

There is a deployment tool used by alot of Rubyists called Capistrano. Its a gem that runs locally on your workstation and can handle a wide array of deployment tasks. It sets up a nice structure to easily allow you to rollback your deployments if you need to as well as run several server side tasks as part of your deployment. I never gave much thought (other than pure envy) to Capistrano as it was tightly coupled to rails deployments. Until now.

I recently found a gem called railsless-deploy developed by Lee Hambley. It simply allows you to use Capistrano to deploy your application without it being a Rails app. So I thought, if I dont need Rails, perhaps the application being deployed doesnt need to be a Ruby app, which means I might be able to deploy a CF app with it! So with much enthusiasm I set out to see what I could do with it.

I was amazed at how easily I was able to start deploying a CFWheels application that I had been working on up to one of my Rackspace Cloud instances. Once the initial configuration was done, deploying a new version was as easy as typing $ cap deploy in the terminal. Capistrano would grab the latest release from GitHub and deploy it to my cloud server, symlink a few config files for me that are shared and save the last 3 releases on the server. How great is that?!

There are a few things you will need to use Capistrano to deploy and I will list them here as well as a basic setup. In part 2 of this post, I will walk you through configuring your application for deployment, setting up your server and deploying your code.

What you’ll need

Since capistrano is a gem, you will need Ruby installed. If your developing on a Mac, you should have it installed already. If you are on Windows, you will have to install Ruby for this to work. There are quite a few blog posts on installing Ruby on Windows, so I will let you handle that on your own.

You will also need SSH access to your server and your server should have a POSIX compatible shell. Most Linux servers should be fine for this. If you are deploying to Windows, I understand there is an extension to Capistrano called capistrano_winrm that may work for you but I havent tried it out.

My workstation is running Mac OS X 10.6 with Ruby 1.9.2 and Git. My server is a Rackspace Cloud Instance running Ubuntu Server 10.10 but any Linux flavor should be fine.

Installation

Once you have ruby and rubygems installed, setup is easy. Simply open your command prompt and install the 2 gems:

$ gem install capistrano
$ gem install railsless-deploy

Thats it, your ready to start configuring your application for deployment and we will do just that in part 2 of this post.

Textmate Bundle For CFWheels Updated

I finally got around to updating the CFWheels Textmate bundle to version 1.02 last night.  Its mostly a few fixes related to snippets but the primary reason for updating it was to add full support for the DBMigrate plugin. Now you can generate migration files and use shortcuts for all of the migration methods in the plugin. Speeding up development just a little bit more.

You can download the full bundle from the RIAForge project page here: wheelsbundle.riaforge.org.

Or you can get instructions on installing it directly with Git on the GitHub project page: CFWheels.Bundle

Please report any issues to the issue tracker on the GitHub page.

CFWheels – Move Finders Into Your Model

One of the principles of CFWheels is not duplicating code. This can be achieved a number of ways, but one in particular can also save you some time. Typically our find() methods used to retrieve data have lots of conditions on them, setting the where clause or the order of the returned results, etc. One way to help clean up your controllers and speed up development is by moving those finders into your model to prevent duplication.

Consider the following controller. We are pulling a list of incomplete tasks ordered by their creation date. Now we could possibly have this same exact line of code scattered throughout our application. Anywhere that we would be pulling a list of incomplete tasks.

component name="Tasks" extends="Controller" output="false" {
	
	public void function index() {
		tasks = model('Task').findAllByComplete(value="false", order="createdAt DESC");
	}
	
}

By creating a custom method on our model object, we can clean up the controller code considerably and make it much more readable. Lets look at what the new controller code would look like.

component name="Tasks" extends="Controller" output="false" {
	
	public void function index() {
		tasks = model('Task').findIncomplete();
	}
	
}

Notice how we only need to call the single method now? Short, simple and concise.

Now lets look at how we achieve this by looking at our new Task model.

component extends="Model" output="false" {
	
	public any function findIncomplete() {
		return this.findAllByComplete(value="false", order="createdAt DESC");
	}
	
}

We simply move the same call we were using before into the new method and return the result. We now prefix the finder with this since we are in fact working with an instance of the Task object.

This really helps to reduce duplication of those parameterized finders in your controllers.

CFWheels – Find Through Association

When I first started learning CFWheels, I was so enamored with how simple it was to retrieve data from the database using the built-in ORM that I would code for days without taking full advantage of how much cleaner and simpler my code really could be. The more I worked with the ORM in Wheels, I learned more and more little tricks to help make my code much simpler. One of those tricks is to stop manually passing foreign keys into my find conditions and make the call through an association. Lets look at an example of how I used to do it.

Lets say we have a Project model that has many tasks and I want to retrieve all of the incomplete tasks for a given project.  Here are our two models:

Project.cfc

component name="Project" extends="Model" output="false" {

	public void function init() {
	  hasMany('Tasks');
	}

}

Task.cfc

component name="Task" extends="Model" output="false" {
	
	public void function init() {
	  belongsTo('Project');
	}

}

Now here is the controller with the old way of doing things:

component output="false" extends="Controller" {
	
	public void function show(){
		project = model('Project').findOneByKey(params.id);
		tasks = model('Task').findAll(where="projectid = #project.id# AND complete = false");
	}
	
}

Notice how I find the project I want and then pass the projectID in the task finder as the foreign key. Now this works, dont get me wrong. But there is a much cleaner way to do this.

component output="false" extends="Controller" {
	
	public void function show(){
		project = model('Project').findOneByKey(params.id);
		tasks = project.tasks(where="complete = false");
	}
	
}

By taking advantage of the relationships in our model, we can call the tasks through the project object and Wheels will automatically handle the foreign key relationship for us.

Isnt that much nicer?

Dynamic Finders in CFWheels

One of the unexpected treats to using CFWheels is how much more readable it can make your code. Im not a big fan of inline comments because I believe in self-documenting code. One of the features of CFWheels that helps to achieve this is “Dynamic Finders”. Here’s a quick example:

Consider this controller:

component extends="Controller" output="false" {

	public void function incompleteTasks(){
		tasks = model('Task').findAll(where="completed = false");
	}

	public void function lastIncompleteTask(){
		task = model('Task').findOne(where="completed = false", order="createdAt DESC");
	}
}

Notice the code is pretty simple, we are retrieving a query of the tasks that are completed by passing the where attribute into our findAll() method with the condition to check for. In the second method, we are retrieving the last incomplete task by passing in the same where clause and ordering the result by the createdAt date in descending order. This is already pretty clean and I love how simple Wheels makes this stuff. But, there is a more readable way to write this using dynamic finders.

component extends="Controller" output="false" {

	public void function incompleteTasks(){
		tasks - model('Task').findAllByComplete(false);
	}

	public void function lastIncompleteTask(){
		task = model('Task').findOneByComplete(value="false", order="createdAt DESC");
	}
}

Notice how we append the column attribute to the method that we want to filter by? In my opinion this is a better example of self-documenting code as its a bit more readable.

So what if we want to filter our results by more than one column? Wheels gives us that ability as well so we still dont have to go back to manually passing a where clause.

tasks = model('Task').findAllByCompleteAndUserid('false,1');

You simply add the other column after the “And” then pass your arguments as a list item to the method. Simple right?

Just a small often over-looked feature that could help make your code just a little cleaner.

ColdFusion on Wheels Version 1.1.2 Released

ColdFusion on Wheels has released version 1.1.3 today. This is mostly a bug fix release, but addresses a couple issues I had in 1.1.1 particularly.

The upgrade is simple, just replace your current wheels folder with the new one from the zip file, reload your application and off you go.

A list of all the issues fixed can be found over at the CFWheels blog.

ColdFusion on Wheels Version 1.1.2 Released Today | ColdFusion on Wheels Blog.

Using Partials In CFWheels To Keep DRY

One of the things I like about CFWheels is that its based on sensible conventions. If you follow these conventions, they can really save you a ton of time writing boiler-plate code as well as configuration. Working synergistically with these conventions are a lot of helper methods that will also reduce the amount of code you have to write as well as keeping your application DRY (Dont Repeat Yourself).
I am working on some new features for SplashCMS and ran into a situation that helped clean up quite a bit of code in some of my views and I thought it warranted a little example to show how nice this feature really is.
I have several places where I want to display a list of snippets in this application. Normally you would just write this code in each of the views that display the listing:

Snippets.cfc (controller)

 

 

index.cfm

 

 
Not really a big deal I know. Pretty simple code to display a small list in a table. But consider this, if you do this 2 or 3 times for each different type of list you have, that could really start to get unruly in a hurry. So to help us keep our views as DRY as possible, we can leverage a feature in CFWheels called partials.
Partials can best be described as CFINCLUDE on steroids. They work exactly like a CFINCLUDE in their simplest form but, are pretty cool in the fact that they can be as simple or complex in functionality as you need. In order to keep things as simple as possible for this post we will simply look at how using a Wheels Partial over a CFINCLUDE is beneficial for our situation and will delve further into some of their more powerful features in another post.
So, in order to keep from repeating ourselves and having as little code as possible in our app, lets look at how we can simplify this. Since we know we are outputting a list of snippets thats returned in our query, we can strip out the code thats used in each view and place it into a partial named the same as our query. By doing this, we are going to take advantage of one of the features of partials that allows us to automatically handle data being passed into it.
First lets look at the code that makes this happen and then I will explain it further.

index.cfm

 

 

_snippet.cfm

 

 
Notice in the view file (index.cfm) how we are calling the partial and instead of passing a file name, we are passing the actual query into the includePartial() method. By doing this, we are telling Wheels that we want it to find our partial named _snippet and loop over it once for each record in the query. Pretty nice, right? We are letting Wheels handle looping over the query and including our display code for us. This is much more portable now. Any place we want to display this list, we can simply call the partial and we have only one file with display code to manage the list. This helps to DRY up our code.
One thing to note. You will notice that Im passing a query named “snippets” plural. However the file Wheels will look for is “_snippet.cfm” singular. Partials are always named starting with an underscore “_” and when Wheels evaluates the query passed into it, it knows we are dealing with a Snippet model and our models are always singular, so the convention is to use singular names for the partials as well. Just think of it like this, the partial is always dealing with only one record at a time, thus its singular.
I hope this helps explain this really cool feature of partials a bit. In my next post we will expand on this example by demonstrating how CFWheels helps you to use grouping in this same partial.