Upgrading to Capistrano 2.0

This past week I finally took the time to update my deploy recipe to the new Capistrano 2.0 format. It’s amazing how DRY the new namespaces feature is. I was able to take all of my custom tasks used for our Apis Networks shared hosting packages and separate them into their own plugin. This way, I’m no longer clobbering the default Capistrano deployment strategy.
It’s as easy as creating a two folders in your vendor/plugins directory. One for the name of the plugin, and one dubbed ‘recipes’. Here’s a typical directory tree:
1 2 3 4 5 |
-- rails_app
-- vendor
-- plugins
-- your_cap_plugin
-- recipes
|
Then, create a file in the recipes directory using any filename you like. Capistrano 2.0 will automatically load any tasks inside this file. Begin naming your deployment recipe inside it’s own namespace, like so:
recipes/tasks.rb
1 2 3 4 5 6 7 8 9 10 |
namespace :my_tasks do namespace :deploy do desc "Restart the FCGI ruby process" task :restart, :roles => :app do puts "Restarting the ruby processes..." # Ignore this confusing unix syntax, it's just for examples sake run "ps lx | grep ruby | grep -v grep | awk '{print $3}' | xargs --no-run-if-empty kill -9" end end end |
To hook your custom tasks into your deployment strategy, add before and after filters to your config/deploy.rb.
config/deploy.rb
1 2 3 4 5 6 7 8 9 10 |
namespace :deploy do # After restarting the ruby process, run the default cleanup task # and run my custom 'post_live' task after "deploy:restart", "deploy:cleanup", "my_tasks:deploy:post_live" desc "This overrides the default Capistrano deploy:restart task" task :restart, :roles => :app do my_tasks.deploy.restart end end |
Re-usable plugin code, fun for every project!
Series: Plug-in arsenal - Paginating Find

Oh, pagination. How you have been tormented over the years in the Rails community. For those of you who have no idea what the devil pagination is, run a search on Google and take a look at near the bottom of the page – You should see “previous” and “next” links, alongside numbers of pages with which to jump to. That’s pagination!
I believe the majority of current opinion on paginating through records is to avoid using the Rails 1.0 built-in Pagination class. In Rails 2.0, it’s been removed and requires the install of an additional plug-in to receive the previous functionality. Cue Paginating Find, a plug-in written by Alex Wolfe of Carboard Rocket. I first learned of Paginating Find via Ilya Grigorik’s blog, as he had written some Helpers & View Partials to support it. Let’s jump in, shall we?
You can install Paginating Find here:1 |
ruby script/plugin install http://svn.cardboardrocket.com/paginating_find |
Paginating Find overrides the default ActiveRecord::find method, and allows a new set of options dubbed :page to accompany the familiar :conditions, :order, etc. We’ll use a Bulletin model for our example:
bulletin.rb (Model)
1 2 3 4 5 6 7 |
def self.find_all_using_pagination( options = {} ) return self.find( :all, :page => { :size => options[:number_of_records], :current => options[:current_page] } ) end |
These options are typically provided by GET variables passed through the URL string to the controller. The new :page option requirs two vars, :size & :current. Use :size to dictate how many Bulletin’s should be pulled from the database per page, and :current to state which page we’re currently viewing. For example, if :current is set to 2, and :size is at 10, we would receive Bulletin’s 11-21.
The best part about Paginating Find is that it works transparently. If you don’t provide the :page option in the find() call, Rails will enact a regular find() call and ignore the fact that Paginating Find is even installed.
Further readings:
- Want to display the page numbers, ‘previous’ and ‘next’ links, as well as CSS styling? See Ilya’s Faster Pagination in Rails article.
- Find more info for this plug-in at the Carboard Rocket page.
A Variation On Rails' Verbose Time Helper
Oh tax season. Does anyone else find that January is the busiest month of the year?
A client of ours recently wanted a custom version of the built-in Rails helper distance_of_time_in_words. Basically, they were looking for a countdown that would dynamically let the customers know how much time they had left to order.
For those unfamiliar with distance_of_time_in_words, you provide it with Date & Time objects and it will state the duration between them in a more human readable format. For instance:
index.html.erb (View)
1 2 3 4 |
<%= distance_of_time_in_words( Time.now, 45.days.from_now ) %> # => about 1 month <%= distance_of_time_in_words( Time.mktime( 2008, 02, 05 ), Time.mktime( 2008, 03, 29 ) ) %> # => about 1 month |
This default behavior is great for informal purposes, such as how long it’s been since a blog article was posted or a comment made. However, I’ve come up with something a little more accurate:
1 2 3 4 |
<%= distance_of_time_in_words( Time.now, 45.days.from_now ) %> # => 1 month, 14 days <%= distance_of_time_in_words( Time.mktime( 2008, 02, 05 ), Time.mktime( 2008, 03, 29 ) ) %> # => 1 month, 22 days |
application_helper.rb (Helper)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
def distance_of_time_in_words( from_time, to_time = 0, include_seconds = true ) from_time = from_time.to_time if from_time.respond_to?(:to_time) to_time = to_time.to_time if to_time.respond_to?(:to_time) distance_in_minutes = (((to_time - from_time).abs)/60).round distance_in_seconds = ((to_time - from_time).abs).round case distance_in_minutes when 0..1 case distance_in_seconds when 0..59 then "#{pluralize( distance_in_seconds, 'second' )}" else "1 minute" end when 2..59 then "#{distance_in_minutes} minutes" when 60 then "1 hour" when 61..1439 then hours, minutes = (distance_in_minutes.to_f / 60.0), (distance_in_minutes.to_f % 60.0) "#{pluralize( hours.floor, 'hour' )}, #{pluralize( minutes.floor, 'minutes' )}" when 1440..1500 then "1 day" when 1501..2879 then "1 day, #{pluralize( (distance_in_minutes.to_f / 60 - 24).floor, 'hour' )}" when 2880..43199 then "#{(distance_in_minutes / 1440).round} days" when 43200..44641 then "1 month" when 44641..86399 then "1 month, #{pluralize( ( distance_in_minutes / 1440 - 30 ).floor, 'day' )}" when 86400..525599 then "over #{(distance_in_minutes / 43200).floor} months" else "over #{pluralize( (distance_in_minutes / 525600).round, 'years' ) }" end end |
1 2 |
<%= time_ago_in_words( Time.mktime( 2008, 03, 29 ) ) %> #=> 1 month, 22 days (assuming current time is February 5th, 2008) |
Welcome to 10.5! Migrating Your Tiger MySQL Databases to Leopard
After quite a bit of deliberation, I’ve decided to move up from Tiger to Leopard. Thankfully, the path to Rails w/ MySQL has been much easier than it ever was on Tiger.
So far, my greatest obstacle has been installing MySQL and bringing my old databases over from my backup. The gracious folks over at Hivelogic have created a brilliant, line-by-line tutorial for building MySQL on Leopard.
After getting MySQL up and running successfully, I completely overlooked the fact that my databases would be wiped clean. I realized the easiest thing to do would be to copy the databases from my Tiger backup.
Note: Both of my MySQL installs are Version 5, so I crossed my fingers hoping they’d be compatible and so far there’s been no problems.
Step 1. Make sure to turn off your current Leopard MySQL install. The command for this in the tutorial is: sudo launchctl unload -w /Library/LaunchDaemons/com.mysql.mysqld.plist which sends the unload command to your plist file.
Step 2. Locate the “data” or “var” folder in your MySQL backup directory. For instance, mine was in /usr/local/mysql on my Tiger install.
Step 3. sudo cp -rf /Volumes/Backup/usr/local/mysql/data /usr/local/mysql Or substitute the paths for the proper source and destination. This will copy the database folder from your Tiger backup to your fresh Leopard MySQL install.
Step 4. sudo chown -R mysql /usr/local/mysql/data mysql Give ownership of the database directory to the mysql user.
Step 5. Start up the server and you should be good to go!
Happy Leopard’ing.
To Trick 'to_xml'

Recently, I’ve been sprinkling more and more XML into my projects. There’s a terrific helper method in Rails dubbed to_xml, which you can run over a collection of records.
At first, I had trouble using this because I was limited to outputting every typical AR attribute for the given model. (ie. I’d receive
Here they are in action:
xml_controller.rhtml (Controller)
1 2 3 4 5 6 7 8 9 |
def compile_slides @slides = Slide.find( :all ) # The :only call is necessary to omit all of the typical attributes render( :xml => @slides.to_xml( :only => [], :methods => [ :name, :cover_photo_url, :xml_url ] ) ) end |
The :only option is overriding the to_xml’s default behaviour of spitting out every attribute, while :methods is stating which custom methods for the AR Model I want to include. For instance, instances of Slide repond to a method named ‘xml_url’:
slide.rb (Model)
1 2 3 4 5 6 7 |
def xml_url return "" if self.url.blank? return "http://#{self.url}" unless self.url[/http\:\/\//] return self.url end ... |
This will give us something like:
slides.xml (XML)
1 2 3 4 5 |
<slide> <xml-link> /articles/1-how-to-search-google </xml-link> </slide> |
Flexible!
Rails hosting
My buddy just sent me a link to a hosting company I haven’t seen before: Site5. I’m curious as to how their customer support is, and how much control you get over your hosting package. (e.g. SSH? Multiple domains? etc.)
We at Carbon Media have always trusted our sites to Apis Networks, which we’ve had nothing but exceptional customer service from. Plus, they were more than accommodating when starting off with Ruby on Rails and helping us get our applications up and running.
However, Site5 does support Rails. If anybody has experience with this company, please leave a comment or send an email to let me know what you think of them! I may just have to start up a personal project to give them a test run…
Series: My arsenal of plug-ins - Bundle-fu
UPDATE: Looks like they’ve added functionality like this in Rails 2.0 using <%= stylesheet_link_tag( “main”, “forms”, “utilities”, { :cache => “frontend” } ) %>. Check out the latest release candidate w/ notes.
After writing about all of the nifty Firefox extensions I use on a daily basis, I had an idea to detail the Rails plug-ins and gems I’m in love with. This marks the beginning.
Tim Harper’s Bundle-fu plug-in was just the thing I was looking for while trying to cut down on the number of server requests per page. All you have to do is wrap both your stylesheets & javascripts in your layout file into separate code blocks, and bundle-fu will take care of the rest.
layout.rhtml
1 2 3 4 5 |
<% bundle( { :name => "styles" } ) do -%>
<%= stylesheet_link_tag( "common", :media => "screen" ) %>
<%= stylesheet_link_tag( "main", :media => "screen" ) %>
... etc.
<% end -%>
|
This outputs a one-liner pointing to one lovely file all your css:
1 |
<link href="/stylesheets/cache/styles.css?20071111142032" media="screen" rel="Stylesheet" type="text/css" /> |
Here’s the install:
1 |
script/plugin install http://bundle-fu.googlecode.com/svn/tags/bundle_fu |
Make sure to read the caveats page as there is a few (as always). I believe the largest is the fact that conditionally loaded stylesheets for Internet Explorer need to be outside of the code block.
Custom 404 Routes & Pages in Rails
Lately, I’ve been using a nice ‘catch-all’ trick in my routes.rb file to send users to a custom 404 page. It’s as simple as throwing this below the rest of your routes:
1 2 3 4 5 |
# If the user has typed an Invalid URL map.connect "*path", :controller => "www", :action => "unrecognized" # Make sure you don't have this default route in there: # map.connect ':controller/:action/:id' # Comment or remove! |
Now, if any invalid URLs are typed in, the app will respond by dishing up the action ‘unrecognized’ from the WwwController.
Here’s where the problem comes in. We recently redesigned a site using Rails, however I noticed that Google was continuing to index the old PHP version of the site just as it always had. Instead of removing the page from it’s index, it was displaying the content of my new custom 404 page. After some research, I realized the reason was my custom 404 page wasn’t a true 404, and was instead sending a 200 Successful HTTP response header instead. This turned out to be a quick fix, but I found it quite undocumented on the net:
1 2 3 4 5 |
class WwwController < ApplicationController def unrecognized render( :status => "404 Not Found" ) end end |
Now our server will dish up the standard ‘404 Not Found’ HTTP response header. It’s just that easy.
Overriding class methods for migrations, a follow-up
I realized I left one important point out from my previous post. I’m sure a few of you may have already picked up on this as well. When you override the class in the migration, you can add in whatever methods you would like the migration to use. We’ll use the same example as before:
004_add_live_pages.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class AddLivePages < ActiveRecord::Migration # Say for instance the Page.rb model has 20 instance methods in it # that we don't want to have affect our migration, but there is # 1 method we want to use below class Page < ActiveRecord::Base # The method 'stripped_name' below is an extension # of the String class def set_permalink self.update_attribute( :permalink, "#{self.id}-#{self.stripped_name}" ) if self.permalink.blank? end end def self.up page = Page.create( :name => "About", :body => "Write your about page content here.", ) page.set_permalink end def self.down end end |
Ta da! Now we can use the ‘set_permalink’ instance method anywhere inside our migration
Overriding class methods for migrations
This trick is an oldy but a goodie. I’m not sure who was first to figure this out but it’s helped me in multiple scenario’s.
Sometimes, when you run rake db:migrate and you’re creating or editing or just messing around with models which already exist, you’ll run into weird errors thrown by the migration. In this case it’s possible that some ActiveRecord callback code (such as before_create :method) is interfering with what you intended. Looks look at an example:
page.rb
1 2 3 4 5 6 7 8 9 10 11 12 |
class Page < ActiveRecord::Base # AR Callbacks after_create :set_permalink def set_permalink last_inserted_record = eval( "#{self.class.to_s}" ).find( :first, :order => "id DESC" ) last_insert_id = last_inserted_record.nil? ? 1 : last_inserted_record.id.increment( 1 ) self.permalink = "#{last_insert_id}-#{stripped_name}" if self.permalink.blank? end end |
004_add_live_pages.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class AddLivePages < ActiveRecord::Migration def self.up # Pages create_table( :pages, :options => 'ENGINE=MyISAM DEFAULT CHARSET=utf8' ) do |table| table.column :name, :string, { :null => false } table.column :body, :text table.column :permalink, :string table.column :created_at, :datetime table.column :updated_at, :datetime table.column :deleted_at, :datetime end Page.create( :name => "About", :body => "Write your about page content here." ) end end |
The easiest way to get around having to worry about Rails automatically filling in the permalink from the after_create call in Page.rb is to override the methods defined in the class just for this one migration. As follows:
004_add_live_pages.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class AddLivePages < ActiveRecord::Migration ### Overriding the Page.rb class file class Page < ActiveRecord::Base; end; def self.up ... Page.create( :name => "About", :body => "Write your about page content here.", ### Now you can define your permalink on create :permalink => "1-about" ) end end |
It may seem like a bit of a hack, and I wouldn’t be surprised if there’s a better way to do this now, but it works for me!
Getting Inside Your Tests
Having trouble tracing the output of your tests? Here’s a quick tip when using functional testing (testing your controllers). Just throw in a simple print or puts call in between your page request (using GET or POST) and before you run your assertions. For instance:
example_test.rb
1 2 3 4 |
get( "index" ) puts @response.body puts flash[:notice] assert( nil, flash[:notice] ) |
Snappy!
Testing formatted RESTful routes
I was searching for a method to testing formatted URLs in Rails, and nothing was popping up in Google so I decided to write about it. All I wanted to check was if my .csv exporting was failing from any code I was refactoring. Here’s the gist of it:
Routes.rb
1 2 3 4 5 6 7 |
map.resources :reports, :controller => "admin/reports", :name_prefix => "admin_", :path_prefix => "admin", :member => { :artist => :get, :event => :get, etc. } |
reports_controller_test.rb
1 2 3 4 5 6 |
def test_should_download_various_reports_as_csv [ "event", "showing", "artist", "box_office" ].each do |report| get( "#{report}", { :format => "csv", :id => 1 } ) assert_response( :success ) end end |
All the magic happens right there, by calling the regular action name defined in the controller, but adding :format => “csv” to the GET parameters hash. And now, my lovely controller will run through this piece of controller code:
reports_controller.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def box_office @report = Reporting::BoxOffice.new( { :showing_id => params[:id] } ) respond_to do |format| format.csv do csv_string = @report.generate_csv send_data( csv_string, { :type => "text/csv; charset=utf-8; header=present", :disposition => "attachment; filename=#{@report.showing.event.name.underscore}_#{@report.showing.id}_box_office_report.csv" } ) end end end |
Easy as pie?
Let's send those users back!
I seem to be posting a collection of my ugliest code, but they’re the methods I find that aren’t documented too well in the world of Rails and are quite possibly some of the more useful tricks I use.
The following code is used to store which page the user was previously viewing. This is helpful if the user has to complete a few steps before viewing content they’ve requested, such as registering for a new account.
application.rb
1 2 3 4 5 6 7 8 9 |
before_filter :create_referral_url def create_referral_url unless request.env["HTTP_REFERER"].blank? unless request.env["HTTP_REFERER"][/register|login|logout|authenticate/] session[:referral_url] = request.env["HTTP_REFERER"] end end end |
The first ‘unless’ condition makes sure that the global request variable used by Rails has an attribute named HTTP_REFERER, and that this attribute contains the last page.
The regular expression in the 2nd ‘unless’ condition filters out any pages you do not want to cache into the session as the referring page. This is helpful if the previously viewed page already has to do with the user’s account, and does not contain any content blocked behind the user’s need for authentication.
Finally, the previous page is cached into a session variable, which we can now redirect the user back to once they have logged in or created a new account. Here’s how we’ll handle this:
In your user registration controller…
1 2 3 4 5 6 7 8 9 10 11 |
def create ... create the user ... redirect_to_next_step end def redirect_to_next_step # If a referral URL exists, send the user to that page (The page they were previously viewing) redirect_to( session[:referral_url] ) and return if session[:referral_url] # Otherwise, off to the home page with 'em! redirect_to( :controller => "home" ) end |
Of course, it’s always better to use named routes or REST instead of straight map.connect routes, but you already knew that. Right?
Custom exception handling
Custom exceptions are a great way of raising errors which you expect to have occur, and which allow you to name and handle them accordingly.
This is ripped out of the wonderful Active Merchant e-commerce library:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
module ActiveMerchant class CountryCodeFormatError < StandardError end def detect_format case @value when /^[[:digit:]]{3}$/ @format = :numeric ... more 'when' statements, etc. else raise CountryCodeFormatError, "The country code is not formatted correctly: #{@value}" end end end |
For some strange reason, when I hit up the Pickaxe for info on exceptions I was met with a very basic usage, and nothing that delved into the use of Custom exceptions down through the stack. So I decided to ask Google for some other skilled Ruby users details of custom exceptions, and also found nothing along the lines of what I was needing. I watched a great video of Jamis Buck and Marcel Molina explaining that custom exceptions are definitely the better way of handling errors, instead of using if, elsif, elsif, else, etc. Jamis has previously written about utilizing custom exceptions when writing everyday code on his blog, but it didn’t delve into enough detail for me again.
After piecing together bits and pieces from all of my resources, and playing around with a ton of various combinations of exceptions I believe I’ve come up with something that definitely makes sense to my coding style. Above is an example of my custom exceptions in action, and I’ve thrown in a bunch of other usages below for the sake of example:
In one of your controllers
1 2 3 4 5 6 7 8 |
def check_show_status # This forces a fallback to the corresponding # rescue if the show is currently locked raise Showing::NotOnSaleError if @showing.locked? rescue Showing::NotOnSaleError flash[:notice] = "This show is currently locked, but will be on sale soon." redirect_to( ticketing_event_url( @showing.event ) ) end |
My Showing.rb model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Showing < ActiveRecord::Base class ShowingError < StandardError end class NotOnSaleError < ShowingError end class SoldOutError < ShowingError end ... etc. etc. end |
Copying a recordset from one table to another
Recently, a client requested a quick addition to one of our software packages that would let them copy content from an existing record to a new one. Essentially, they wanted the option of copying previous ticket prices and dates for a showtime to a new showtime. There’s a multitude of ways to implement this functionality, and for our purposes I found the best method was to use a bit of AJAX.
Read the rest of this entry

