For previous projects I never used Heroku, sometimes because I needed tools not available on the platform, other times because I had other options that were more interesting, price-wise.
My last side-project sounded like a perfect fit to trial Heroku though. My conclusion as you may have guessed is that Heroku is really addictive and sweet to use, I encourage you to give it a try.
Disclaimer: this is not a sponsored post for Heroku or MongoHQ – I’m just really happy with my current experience.
The site itself is ToutPourMoniPad.com – housses et étuis pour iPad – a place that aggregates the cases, sleeves and protections we have found for the iPad, from vendors that ship to France without international shipping costs. Currently 100+ references and counting.
This post is not intended to be a nice layed-out article, rather a repository of links and code snippets I’ve been using and found practical.
Overall impression
The deployment was absolutely quick (less than 30mn apart from DNS config) and flawless. The site is quite snappy as well, and the uptime has been wonderful.
Technical overview
- I used the new Bamboo stack which allows Ruby 1.9.1
- the app itself is based on Sinatra with HAML and SASS
- I struggled a bit to get the DNS to work but it went ok (see docs here) – maybe I should have tried using Zerigo as suggested
- I used Bundler for the gems, as advised
- the database started with Sqlite then we moved to MongoDB 1.4, hosted on MongoHQ (free plan)
- I could not get exceptional to work (but that’s probably linked to how my app is configured), so I used custom email
- the data aggregation system is built on TinyTL, ActiveWarehouse-ETL unreleased tiny brother, just like my ruby/rails screencasts aggregator previously
- as I used a lot of data (html, xml, csv) caching locally, I used api-cache which works wonders
- image resizing is done on my dev machine using imagemagick via command line, then pushed via git
Exceptions notifications
For some reason, I could not get Exceptional to work with my Sinatra setup. Here’s what I used (see below for email setup):
error do
e = request.env['sinatra.error']
msg = ...
send_email('Exception!',msg)
haml :'500'
end
Graphical tips
I used Google web fonts, jQuery corners, Compass and SASS to finetune the blueprintcss-based layout.
Notes on MongoDB
This site relies heavily on a ETL process in the background.
I’ve been playing a lot with ETL and MongoDB recently and I find that this database is very convenient to munge data coming from different sources and in different formats (html, xml, csv).
Being able to add any number and variety of columns on the fly as you integrate the data sources is a big win: MongoDB is very interesting for that matter.
MongoHQ offers a free plan to get started so I took the plunge. The internal aws connection between Heroku and MongoHQ seems to work fast enough.
Data caching
Api-cache is worth a look to cache just about anything. Quick snippet:
require 'moneta/basic_file'
preprocess {
# setup the cache store, here using file storage
folder = File.dirname(__FILE__) + '/cache'
FileUtils.mkdir(folder) unless File.exists?(folder)
APICache.store = Moneta::BasicFile.new(:path => folder)
}
def some_cached_operation(xxx...)
APICache.get(the_key, :cache => 60*60*24*10, :valid => 60*60*24*4, :period => 2) do
process_some_heavy_download_with_polling_limits
end
end
each_row { |row|
row[:data] = some_cached_operation(xxx...)
}
Heroku tips
Migrating stack to MRI 1.9.1
I started with the wrong stack but this can be easily changed:
$ heroku stack:migrate bamboo-mri-1.9.1
Database setup
By default the database uses a locally running MongoDB instance. I update the production database from the developer workstation (no heroku worker so far, although that may come), by using env vars for setting up the connection:
if ENV['MONGOHQ_HOST']
puts "Running on MongoHQ"
MongoMapper.connection = Mongo::Connection.new(ENV['MONGOHQ_HOST'], ENV['MONGOHQ_PORT'])
MongoMapper.database = ENV['MONGOHQ_DATABASE']
MongoMapper.database.authenticate(ENV['MONGOHQ_USER'],ENV['MONGOHQ_PASSWORD'])
else
puts "Using local database"
MongoMapper.database = 'tout-pour-mon-ipad'
end
On traditional hosting you would put a config.yml path in the Capistrano shared folder, here you use vars that are managed by Heroku itself, and kept between deployments.
$ heroku config:add MONGO_HOST=flame.mongohq.com ....
These variables are then set in the application ENV.
Email setup
I use smtp for the contact form and simple exception notifications. As suggested by Heroku docs, I used Pony and the free sendgrid add-on.
require 'pony'
TPMI_SMTP_OPTIONS = {
:address => "smtp.sendgrid.net",
:port => "25",
:authentication => :plain,
:user_name => ENV['SENDGRID_USERNAME'],
:password => ENV['SENDGRID_PASSWORD'],
:domain => ENV['SENDGRID_DOMAIN'],
}
def send_email(subject,html_body)
Pony.mail(:to => '...', :from => '...',
:subject => subject,
:html_body => html_body,
:via => :smtp, :via_options => TPMI_SMTP_OPTIONS)
end
Conclusion
I’m very happy with the setup and overall experience so far, and it has been very nice to have no hosting cost at all to trial the idea. I will definitely switch to a paid plan at some point, and will try to experiment with larger sites.
I intend to work more on the site and will blog about the technical aspects here, so stay tuned.
The comments system is brand new - don't be afraid to comment!
- HackerBooks.com (books from StackOverflow and HackerNews) (March 4th, 2011)
- On JRuby, Resque and Windows (August 2nd, 2010)
- Monitoring File Changes and Getting Notified via Growl (February 14th, 2010)
- How to use Google Calendar and Rufus-Google for Basic Time Tracking (November 27th, 2009)
- Using JRuby to prototype VST plugins (November 17th, 2009)
- Introducing Learnivore.com (September 15th, 2009)
- How to create small, unique tokens in Ruby (July 2nd, 2009)
- Detecting Which Ruby Interpreter is Running (JRuby, IronRuby) (March 4th, 2009)
- How to create an empty Rails Edge application (January 28th, 2009)
- How to Freeze Gems with Rails >= 2.1 (December 23rd, 2008)
- Thoughts on IronRuby and .Net Testing (December 1st, 2008)
- How to Retrieve Delicious Tags and Number of Bookmarks for a Given Url (November 30th, 2008)
- Fixing Symbol not found _rl_filename_completion_function (November 6th, 2008)
- How to Generate a Gradient for your CSS using RMagick (October 21st, 2008)

