Young delta heart

Scratch your itch: Tiny apps with Ruby, Rack and Heroku.

A ramble through the bramble.

Humans like to create artefacts

Either to share with others or to keep a personal record, it helps bring meaning to life and is an important part of that yearning we have to leave a little part of our existence behind. Sometimes when you are dealing with hardship, or just trying to get something done creating a record helps you progress.

It helps us work.

Making lists, writing notes, and sketching on paper. These physical or digital artefacts help gather momentum towards a goal as well as spurring on a feeling of continual creation when travelling towards that goal.

Imagine trying to achieve something really substantial keeping everything in your mind, resisting the temptation to deposit knowledge via a physical action you will likely find you don't get very far, or get easily distracted on the little things.

Now imagine the scenario when you wake up, still in bed, early morning, tired and not ready to get up. Maybe you try and get your brain in gear thinking about all the things you are going to do once you get out from under the duvet. You make a list in your mind; have a shower, feed the cats, remember some towels for yoga and grind some coffee - oh shit did I run out?

“Well, I'll remember to pick some up after yoga”.

If you are anything like me, you spend 10-15 minutes doing this dance, a half baked promise to yourself before physically forcing yourself out from under the warm covers and into the cruel cold room.

That somewhat inane situation is a lot like a task without artefacts, your brain cannot hold all of the actions and steps it needs to take towards a distance goal, so you must break these down into actions, steps and decisions. Writing down, or at least saving state helps you move on and progress.

I imagine you shaking your head in semi-bored disbelief.

A little help from my friends

Those that know me personally or perhaps follow my tweets should know that 1653 days ago I gave up drinking alcohol. Without detailing the grim circumstances, one can suffice to say a hard thing to do.

For me, each days elapse is met with a nice pat on the back, and I wanted a little reminder of that I could call upon when I wanted such a little lift.

So I made a tiny app that tells me how many days it has been since I gave up the old vino.

Taking approximately 3 minutes to write and deploy it is now accessible from anywhere, on my phone, and in the pub whilst I watch my mates slowly absorb themselves.

I'm a one man guy, is me.

What I would like to share today are the tools I used to get this little app together so quickly and published on the web so easily.

Of course, the unspoken tool is HTML/CSS which I output to the browser, with that ticked off the other pieces of the puzzle are as follows:

Ruby

Unless you have been asleep or trapped in a closet, you will undoubtably know what Ruby is; the fantastic programming language that powers the framework that changed the way I wrote web applications, yes you know that one called Rails.

This will be my fifth year with Ruby as my language of choice and our relationship is as strong as ever, yet I don't feel the urge to persuade you, this isn't some sales pitch, my friend.

Rack

Rack is basically a very simple interface between web servers and a web framework. For example, the popular Ruby framework Rails now runs on Rack, which means any web server that is Rack compatible will run Rails apps (and means any new servers that appear just need to speak Rack to run Rails and countless other Ruby frameworks).

Rack makes me think of boobies, which apparently is sexist.

This is very cool, because now we have a common way to interface with lots of different web servers via a simple API.

Whilst Rack was designed to be used by web framework authors and not necessarily end users (in this case programmers), the same API that is used by said frameworks is simple enough for you to use to deploy a very small application that doesn't require the overhead of a whole web framework.

You can even write software that sits in between your application framework and with Rack itself, this is often referred to as the middleware and can take the HTTP request (ie a GET request from a browser) and decide whether to process the response itself or pass it on to the web framework itself. Rails has middleware called Metal, which allows a developer to decide (in code) whether to send the request to Rails, or deal with the request there and then. This means you can bypass the potentially slower route of the whole framework and deliver certain end-points fast as your mother likes it.

One example of this is to handle caching, instead of having to spawn Rails to decide if you can deliver cached content, you can do this via middleware and deliver the cached content without ever needing to add the expense of bothering your big ol' Rails app.

The depth of Rack is beyond the point of this article, but should you want more information a good place to start might be on the official page, but google is also your friend.

Heroku

I have a major crush on Heroku, I'm not dumb enough to try and decipher, or even suggest that a cloud based hosting provider has a gender, but either way I'm smitten for Her(oku) in a big way.

Possibly the easiest and most grin inducing hosting platform I have ever used, if you have never seen what the whole thing is about, here is a quick run down.

Heroku is a cloud hosting platform, that allows you to deploy you apps via a git workflow. I already use git for versioning my code (which I might add have major love for git (I hear you - oh Jase that is très passé) but being super easy to work with and helping me instead of stabbing me in the face like subversion used to who can blame me. So when I learned I could deploy my code via a git push, it turned my frown upside down.

Guess what, Heroku knows what to do with Rack apps, so as long as your app is Rack compliant, it will run on Heroku with no setup needed.

It's starting to get a bit too geeky around here, so let me get back on the fence and say:

With Heroku you get your idea live very quickly

Minimal setup, very little effort, and all for free (low resource apps don't cost anything). It is the perfect solution to launch our little itch apps to the world.

Getting started

Before I dive into the example, I need to cover some of the basics. I'm also going to assume you have Ruby, and RubyGems installed on your system. If you have a mac with a recent version of OSX then you will do out the box, but you can also install it from source.

If you are on windows, well I have no idea, poor you etc. If you are on Linux I imagine you know what you are doing so I'll shut up.

Also if you are a programmer this might be a chore to read, but I'm also assuming that you are interested, and therefore you need a little primer. Don't get too hung up on the code, the real point of this article is the higher level concept and hopefully getting you to discover the component parts incase they haven't crossed your path before.

Call on me.

A Rack app is required to respond to a method named call() which gets passed some details of the server environment that the HTTP request (that you need to process) has come from.

Thankfully the call() method exists in a special type of Ruby object called a Proc, which is basically just a special function that you can create to use later on in your application. If you read my previous article, you may remember we created a reference to our jQuery widget which was a plugin (fancy name for a function) and applied it to our html via javascript.

Back with Ruby and without going too deep, lets look at a very simple example of a Proc:

  1. >> hello_method = Proc.new { |name| "Hello #{name}" }
  2. => #<Proc:0x000000010169a328@(irb):16>
  3. >> hello_method.call("Mom")
  4. => "Hello Mom"

First we define a variable called hello_method and assign a Proc object to it, we then pass what is known as a block (think of it as a block of code - or closure) into to the initialize() method via Proc.new() which creates an instance we can execute later.

Then we use the call() method on our Proc (via the hello_method reference) passing in the string "Mom", and the block we defined the in the line before is evaluated and returns "Hello" concatenated with whatever we passed into the block (referenced as a local variable called name). This as you can hopefully see returns "Hello Mom".

Extra credit

If you have ruby installed, try typing irb into your computers terminal and entering the lines that start with >> into the prompt (you don't need to type the actual >> into the prompt). irb is the interactive ruby shell which allows you to execute arbitrary bits of ruby on the fly.

Back to Rack

First you need to install the Rack gem, which will allow us to run our app.

gem install rack

As we mentioned, Rack expects our application to respond to a method named call(), it also expects that method to return an Array with three elements:

  1. HTTP Status response (for example 200 which means the request was successful).

  2. A hash of any HTTP headers to return to the server, such as the content type and length.

  3. The body of the response (normally a html file, but could be xml or json for example).

Such an array may look like this:

[200, {'Content-Type'=>'text/plain'}, "Hello world"]

Which would return the text "Hello World" to your browser.

Putting this all together into a working Rack app would look like so:

Hello World App (download source)

  1. app = lambda { |env|
  2. [
  3. 200,
  4. {'Content-Type'=>'text/html'},
  5. "Hello World"
  6. ]
  7. }
  8. run app

Running the Hello World app.

  1. Download the hello_world.ru file from the previous code block.

  2. Open up your terminal, such as Terminal.app on the mac.

  3. cd /path/to/your/downloads/folder

  4. then type rackup hello_world.ru (it will hopefully do nothing, and wait for connections).

  5. Visit http://localhost:9292 in your web browser of choice.

  6. Smile and nod.

  7. Close your terminal, or hit ctrl+c inside your Terminal to quit rack.

Woah there Jase, great but what the hell is that lambda thing?!

Well, for the purposes of sanity, lets just say that lambda is another way of doing Proc.new() - there are slight differences, but none that are relevant in this context so don't worry about that - the important thing is you have seen them both so any other examples you find along the way should make sense.

You can also see after our main code block we are calling a method run and passing in our refrence to the Proc via our variable app.

This is the actual launch command for Rack which gets your app up and running ready to take requests.

Moving on

So my sober counter app is potentially the simplest app ever, it really doesn't deserve to be called an application but it does go some way in showing how easy these kind of development strategies are, and if you have never played with Rack, Heroku or even Ruby then maybe I have piqued your interest.

Chances are you don't really care about my how many days I've saved grace, so maybe we'll do something a little closer to home. So how about a one line app that tells us what week of project52 we are on?

Hey man, give me a break I got a mind full of blanks.

The code to work out the current week is:

week = DateTime.now.strftime("%V") #=> "02"

Which is the ISO-8601 date standard, which may or may not be how people are doing p52 counting, but who cares as long as you are pumping something out at least once a week, right?

The only other dependency is a html file that is sucked into the app block and has a placeholder dynamically replaced with the current p52 week.

The HTML template (download source)

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>What week is Project52 on?</title>
  5. </head>
  6. <style>
  7. body { background: #bebebe; font-family: "Sathu", "Helvetica", Arial; color: #333; text-align: center; }
  8. h1 { font-size: 3em; text-shadow: #eee 1px 1px 1px; margin-top: 3em; line-height: 3em; }
  9. h1 span { font-size: 4em; line-height: 0.5em; }
  10. </style>
  11. <body>
  12. <h1>Project52 week is <span>[CURRENT_WEEK]</span>/52.</h1>
  13. </body>
  14. </html>

To read in the index.html template file, and replace the placeholder [CURRENT_WEEK] we do:

body = File.read('index.html').gsub(/\[CURRENT_WEEK\]/, week)

We return the body variable in our code block just like we did with our Hello World example, and I have added a few extra headers to the response.

"Content-Length" => body.length.to_s

Tells the server the expected length of the response, which is the length of our html that resides inside the body variable and

'Cache-Control' => 'public, max-age=3600'

which caches the result of the page (expiring after 3600 seconds or 1 hour) as this will make subsequent requests to our page nice and fast (the caching is provided by Heroku via Varnish).

Here is the whole thing:

Current week app (download source)

  1. run lambda { |env|
  2. week = DateTime.now.strftime("%V")
  3. body = File.read('index.html').gsub(/\[CURRENT_WEEK\]/, week)
  4. [
  5. 200, {
  6. 'Content-Type'=>'text/html',
  7. 'Content-Length' => body.length.to_s,
  8. 'Cache-Control' => 'public, max-age=3600'
  9. }, body
  10. ]
  11. }

if you are playing along at home, here is a both the required files as a zip for you to run rackup and view in your browser.

Deploying to Heroku

This is the final piece of the puzzle, all you need to do is have a free account with Heroku, give them your public ssh key and then install the heroku gem.

gem install heroku

Lets imagine we have created our application, but as it is a quick app we haven't setup git yet, no bones lets do that now as Heroku requires it (you may need to install git on your system first).

  1. cd p52_app
  2. git init
  3. git add .
  4. git commit -m "my week counter app"

Without getting bogged down in how to use git, the above basically just initialises your app folder as a git repository, adds all the files inside it to the repository and commits the files with the commit message "my week counter app".

With that all set, you are ready to create your app on Heroku which we will call p52week via the command heroku create p52week

  1. $ heroku create p52week
  2. Created http://p52week.heroku.com/ | git@heroku.com:p52week.git

All you need to do now is deploy the app, and get on with your life by typing git push heroku master

  1. $ git push heroku master
  2. Counting objects: 5, done.
  3. Delta compression using up to 2 threads.
  4. Compressing objects: 100% (3/3), done.
  5. Writing objects: 100% (3/3), 311 bytes, done.
  6. Total 3 (delta 1), reused 0 (delta 0)
  7. -----> Heroku receiving push
  8. -----> Rack app detected
  9. Compiled slug size is 4K
  10. -----> Launching......... done
  11. http://p52week.heroku.com deployed to Heroku
  12. To git@heroku.com:p52week.git
  13. a17392a..44df591 master -> master

And we are done.

Your little app is ready for the world, just in time for the kettle to boil ready for a nice cuppa.

Check it out http://p52week.heroku.com/, and until next week, I bid thee adieu.