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.

Apache Restart Error In OS X

I know quite a few of you are using OS X for your ColdFusion development so I thought I would post this in case anyone else has run into it.
On My new iMac, I was making a few changes to the apache config and issued a restart using the apachtctl restart command. I was greeted promptly with the following error:

/usr/sbin/apachectl: line 82: ulimit open files: cannot modify limit: Invalid  argument

Now I know this works, I had been using it on my MacBook Pro to restart apache. So I did a little digging and apparently in the OS X 10.6.5 update, the apachectl script was updated and a bug was introduced. Luckily its a simple fix, head to line 64 of the /usr/sbin/apachectl file and change the following line:

ULIMIT_MAX_FILES="ulimit -S -n `ulimit -H -n`"

to this:

ULIMIT_MAX_FILES=""


Save the file and your apachectl script should work without issue.

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.

Linking To Files In ColdFusion Errors

Its been well over a year ago that I dropped developing with CFEclipse. I grew tired of the endless resources it consumed and it always seem very slow. Of course this wasnt due to the the CFEclipse plugin, it was the Eclipse platform that it was built on. Now with Adobe releasing the beta of ColdFusion Builder I decided I would give it a try again. But after an hour or so of playing with it, I still wasnt sold.
So, it was back to Textmate for me. Using Textmate for devlopment has been a pure joy. Its so easy to add new functionality specific to the language you are using with its Bundles that I find myself looking for new ways to make everything faster. I have created a bundle for CFWheels that provides function insight along with snippets for just about everything in the framework. This runs on top of the excellent ColdFusion Bundle that Rob Rohan is working on. I have hotkeys for just about everything I need with the exception of getting me another cup of coffee.
I have heard from guys on mailing lists time and time again talk about the productivity they have gained since moving to Textmate or its port to Windows called “E-Texteditor”.
I came across a feature in the Textmate manual yesterday that I was interested in and wanted to see if I could exploit it in some way. This feature was the ability to link directly to files on your dev machine from other applications, even in html. Hmmm, so does this mean I could create an error page that would link directly to my development files?
So, since I use Railo for my local development mainly, I opened up the web admin and found the Error section to see which error file I was using for this particular project. I was using the error-neo.cfm template that mimics the output of the ColdFusion error pages, so I opened it up in Textmate to see how the file list was output.
Now Im not going to gaurantee that the ColdFusion error code is the same as the Railo error code but its probably pretty similar and should work just as well. So this is what I found for the error output:

The error occurred in #catch.tagcontext[idx].template#: line #catch.tagcontext[idx].line#
Called from #catch.tagcontext[idx].template#: line #catch.tagcontext[idx].line#


Wow, that looks simple enough. So back to the Textmate documentation I went to see exactly “how” I build out the link structure. The URL structure in HTML is pretty simple. There are only 3 parts to it that you have to build out.
 

  • url – the (file) URL to open
  • line – the line number to jump to an place the cursor when the file is opened
  • column – the column to place the cursor when the file is opened

 
Now going back and looking at our error code. We know the code is outputting the full path to the file and its also displaying the line number. So we have 2 of what we need. The Column attribute is optional and we dont really need it.
So here is what our link should actually look like using the Textmate format and our CFCATCH variables:


txmt://open/?url=file://#catch.tagcontext[idx].template#&line=#catch.tagcontext[idx].line#

Pretty simple right? Now here is the same code block with the URL’s in-place to allow you to open any of the files in the error stack.

The error occurred in #catch.tagcontext[idx].template#: line #catch.tagcontext[idx].line#
Called from #catch.tagcontext[idx].template#: line #catch.tagcontext[idx].line#


Now when you encounter an error in your application and the cfcatch message is displayed with the file listing. You can simply click on the file and it will open to the exact line in Textmate. No digging through the file list to find the file.