Have you ever wanted to build a super basic ruby web app? Maybe a single-page sort of thing, something that displays the temperature in your backyard or the number of emails in your inbox. The sort of thing where a simple HTML page won’t work, but a framework is overkill.

PHP got its start doing this sort of thing. While you can build object-oriented MVC frameworks with PHP, the reason so many people started using it was because if your server was set up for it, you could just rename index.html to index.php and paste in some code between . Done.

Alas, it’s never been quite that simple with Ruby, but we do have Rack.

About Rack

What’s Rack? It’s how frameworks like Sinatra, Rails, Hanami, etc. talk to web server software. Or as the Rack website puts it “Rack provides a minimal interface between webservers that support Ruby and Ruby frameworks.”

Also from the Rack website, here’s a super simple Rack app:

run Proc.new { |env| ['200', {'Content-Type' => 'text/html'}, ['get rack\'d']] }

This would go in the file config.ru. This file tells the rackup command what to do to run your application. (Ever notice that Rails apps have a config.ru?)

The command ‘run’ tells it what to run. The thing it runs is a Proc that gets passed something called env, then returns an array with ‘200’ (as in the HTTP status code OK), a hash of response headers, and an array of strings.

While it does a great job of showing just how simple the interface is, the code above isn’t very exciting or useful. Let’s make something that does stuff! Inspired by isitchristmas.com, I bring you: Is it April Fools?

Building a Rack App

To start with, let’s write an index.html.erb:

<!DOCTYPE html>
<html>
  <head>
    <title>Is it April Fools?</title>
  </head>
  <body>
    <% if self.april_fools? %>
      <h1>YES</h1>
    <% else %>
      <h1>NO</h1>
    <% end %>
  </body>
</html>

Now let’s build something more classy/object-y than a proc. Here’s my_rack_app.rb:

require 'erb'

class MyRackApp
  class << self
    def call(env)
      ['200', {'Content-Type' => 'text/html'}, view]
    end

    def view
      [ERB.new(template).result(binding)]
    end

    def template
      File.open('index.html.erb', 'r').read
    end

    def april_fools?
      Time.now.strftime('%m%d') == '0401'
    end
  end
end

In case you’re wondering, ERB#result accepts an optional instance of Binding, which lets us pass in our current execution context. That’s how we’re able to use the self.april_fools? method within the erb file. If we didn’t need this, we could just call #result with no arguments, and it would be given a new context.

Because we defined self.call, the MyRackApp class will behave like a proc. This will allow us to make config.ru much prettier:

require ‘./my_rack_app’

run MyRackApp

So easy!

Running Our Rack App

To see it in action, use the rackup command in the same directory as your config.ru. rackup runs on port 9292 by default, so go to http://localhost:9292 in your browser to see it.