sinbook: simple sinatra facebook extension in 300 lines of ruby

(c) 2009 Aman Gupta (tmm1)

Usage

require 'sinbook'
require 'sinatra'

facebook do
  api_key  '4579...cbb0'
  secret   '5106...2342'
  app_id   81747826609
  url      'http://apps.facebook.com/myappname'
  callback 'http://myappserver.com'
end

get '/' do
  fb.require_login!
  "Hi <fb:name uid=#{fb[:user]} useyou=false />!"
end

Features

sinbook provides a simple `facebook` helper (also aliased to `fb`).

  >> fb.valid?
  => true                              # valid (authenticated) request from facebook's servers

  >> pp fb.params
  {
    :logged_out_facebook => false,     # request came from a user logged into facebook
    :added => true,                    # user is logged into our app
    :user => 1234,                     # user's facebook uid
    :friends => [1,2,3],               # list of user's friends
    ...
  }

  >> fb[:user]                         # [] is aliased to params[]
  => 1234

  >> fb.callback
  => 'http://apps.facebook.com/myappname'

  >> fb.callback('/homepage')
  => 'http://apps.facebook.com/myappname/homepage'

  >> fb.url('/images/static.gif')
  => 'http://myappserver.com/images/static.gif'

  >> fb.appurl
  => 'http://apps.facebook.com/add.php?api_key=4579...cbb0'

  >> fb.addurl
  => 'http://www.facebook.com/apps/application.php?id=81747826609'

  >> fb.redirect('/welcome')           # redirect using an fb:redirect tag

  >> fb.require_login!                 # redirect to addurl page unless logged in

The helper can also be used to make API calls

  >> fb.users.getInfo :uid => 1234, :fields => [:name]
  => [{'uid' => 1234, 'name' => 'Frank Sinatra'}]

  >> fb.groups.get :uid => 1234
  => [{'name' => 'Sinatra Users'}]

  >> fb.profile.setFBML :profile => 'hello world'
  => true

  >> fb.profile.getFBML
  => 'hello world'

Other Options

facebook do
  symbolize_keys true
end

>> fb.groups.get :uid => 1234
=> [{:name => 'Sinatra Users'}]

Standalone Usage

require 'sinbook'
fb = Sinbook.new(
  :api_key  => '4579...cbb0',
  :secret   => '5106...2342',
  :app_id   => 81747826609
)

>> fb.friends.get :uid => 1234, :session_key => 'user-session-key'
=> [4321,4567,9876]

Local Development

To develop locally, use ssh to setup a reverse tunnel to your external server.
For example, set your callback url to http://myserver.com:4567/, and run:

  ssh -gNR 4567:localhost:4567 [email protected]

Then, simply launch sinatra on your local machine. Facebook will make requests to
http://myserver.com:4567/ which will be forwarded to port 4567 on your local machine.

For facebook connect, I generally add a CNAME on my domain for fb.myserver.com, and setup
nginx on my server with the following:

  server {
    server_name fb.myserver.com;
    location / {
      proxy_pass http://localhost:4567;
    }
  }

Make sure your connect url is set to 'http://myserver.com' and the base domain is set to 'myserver.com',
so that the fb.myserver.com subdomain works.

TODO

* Add a batch mode for api calls:

    groups, pics = fb.batch do |b|
      b.groups.get :uid => 123
      b.users.getInfo :uids => 123, :fields => [:pic_square]
    end