Utilizing Jekyll with Sinatra on Heroku for a Facebook App

I love working with Jekyll. It’s very nerdy for what it does since the final output is a static HTML server which is awesome for smallish projects not utilizing a database. Low and behold, most Facebook apps are just that — a show case of some special feature that only fans of the page can access. Forget using Flash anymore, this is quicker and simpler and of course you can mixing some HTML5.

Using Jekyll, Sinatra (for the Rack aspect) and hosting it on the awesome Heroku stack makes creating Facebook apps a breeze — if you know the steps to begin with.

Things you will need and know

  1. A Heroku account - free to signup and also provides a free development account
  2. Jekyll installed - Check out the docs for setup and installation
  3. Basic knowledge on how to create a Jekyll project
  4. A Facebook developer account to create the app - this post is not about creating one or setting up the app on Facebook. You should have a working knowledge of creating the app through their tools.

Before I get started with the basic code, I want to extend thanks to Jesse Storimer on his post to get me started with how to run Jekyll output on Heroku and also this Stack Overflow response for the JavaScript “Like” gate solution.

The setup

In order to run a Jekyll project on Heroku, you need to fake out Heroku into thinking it’s a Rack app. This is done by making the project run through Sinatra. Using Jesse’s masquerade code with some minor modifications for ability to run on Facebook you can create these files in your base Jekyll project folder.

Gemfile (always good to utilize this)

source ‘http://rubygems.org'
gem ‘sinatra’

configu.ru

require './masquerade'
run Sinatra::Application

masquerade.rb

require 'rubygems'
require 'sinatra'

set :public, Proc.new { File.join(root, "_site") }

# This before filter ensures that your pages are only ever served 
# once (per deploy) by Sinatra, and then by Varnish after that
before do
      response.headers['Cache-Control'] = 'public, max-age=31557600' # 1 year
end

get '/' do
      File.read('_site/index.html')
end

post '/' do
      File.read('_site/index.html')
end

Things of note

The masquerade.rb file sets up Sinatra to default to the site/index.html structure from which the app runs.

In the config.ru file I changed the path to the required masquerade file. Heroku would throw an error and crash because it could not find the required rb file when launched. Better to explicitly tell it were to find the file than not.

For Facebook iFrame tabs, Facebook sends a POST request to your app for it to return the actual page data. I added to the masquerade.rb file the route for the POST request. Initially, I only had the GET request so the app would return Facebook a 404 error thus resulting in an ugly h1 tag wrapping “Not Found”. Good luck finding a solution that until you check your heroku logs.

Extra credit - make visitors like your page

Since this post is about a static HTML application, there was no need for a dynamic language such as Ruby on Rails using Ruby or even PHP to utilize the Facebook SDK. If you want to setup what is known as a Like Gate you would need to add the ability to check the current user session information. Unfortunately, you can’t do that very easy with JavaScript, but you can utilize the JavaScript SDK and a simple query of current user ID and page ID. Easiest way is to wrap all of below in the asynchronous solution Facebook provides

FB.init({
appId: ‘YOUR APP ID’, 
status: true, 
cookie: true,
xfbml: true
        });
FB.login(function(response) {
    if (response.session) {
    var user_id = response.session.uid;
    var page_id = “YOUR PAGE ID”; 
    var fql_query = "SELECT uid FROM page_fan WHERE page_id = "+page_id+"and uid="+user_id;
    var the_query = FB.Data.query(fql_query);
    the_query.wait(function(rows) {
    if (rows.length == 1 && rows[0].uid == user_id) {
    // The user has liked your page
    } else {
    // The user has NOT liked your page
    }
    });
    } else {
    // user is not logged in
    }
});

Hope this helps whomever has stumbled upon this post. I know I will utilize it to remember the hoops I had to jump through to get this to work.

Update

I created a basic default project available for cloning on Github utilizing Jekyll, Sinatra and Compass from discussion above. Feel free to check it out Jekyu.

Filed under: Code