by Shane Vitarana and David Clements

$9
Hooking into the network
Rails on
Facebook
2
Rails on Facebook
©2008 Shane Vitarana and David Clements
Every effort was made to provide accurate information in this document. However,
neither the authors nor Topfunky Corporation shall have any liability for any errors in
the code or descriptions presented in this book.
This document is available for US$9 at PeepCode.com (http://peepcode.com). Group
discounts and site licenses can also be purchased by sending email to peepcode@
topfunky.com.
"Rails" and "Ruby on Rails" are trademarks of David Heinemeier Hansson. "Face-
book" is a trademark of Facebook. Other names are mentioned without any intention
of infringement on the trademark.
contents
Introduction 5
Why Facebook?
Social Data
The Facebook Platform 7
The Facebook API
FBML
FBJS
Getting Started 15
Facebook Signup
Facebooker
Configuration
Hello World
Development Environment
Facebook Authentication 23
Verifying Request
Authenticating a User
Getting Social Data 26
User and Friend Data
Photos
Events
Anatomy of an App 28
Integration Points
The Profile Page
New Profile Application Tab
News Feed and Wall
Notifications
Emails
Invitations
Info Section
New Profile Publisher
Testing 52
Functional tests
Test accounts
Ruby Footprints App 54
Routes
Models
Advanced Topics 58
FBML and Image Caching
Bebo
Appendix: Terminology 62
Appendix: Models 63
The Authors
Credits
Revisions
4
5
Introduction
chapter 1
This book assumes that you know how to develop Rails applications
and have a basic understanding of Facebook, or at least have setup a
Facebook account and played around with it a bit. Occasionally you
will fnd links to the Facebook wiki on various topics; this is because
the Facebook development platform is constantly changing and the
wiki is the best place to get the latest information about what is going
on with a particular feature. These links will look like this: Developer
Wiki Link (http://wiki.developers.facebook.com/index.php/Main_Page).
Throughout the book, we will be citing examples from a sample appli-
cation called Ruby Footprints. Ruby Footprints is included with this
book and also available on GitHub (http://github.com/digidigo/ruby_footprints/
tree/master). We will keep this application up-to-date with Facebook API
changes and anyone is free to contribute to it.
Why Facebook?
People are spending an increasing amount of time on social net-
works (http://lsvp.wordpress.com/2007/07/23/follow-up-on-top-social-networks-by-
engagement). The ability to engage online with friends is slowly replac-
ing more traditional forms of entertainment, like watching television.
Applications on Facebook are popular because access to them is
super easy from Facebook. Apps are discovered by getting invita-
tions to them from your friends. Since people trust their friends more
than random people on the web, they are more likely to try out your
app. Furthermore, apps on Facebook don’t require separate logins.
Users are more likely to use an app if they don’t have to sign up yet
again on another site. The social elements of Facebook apps are also
responsible for their popularity. It gives people a chance to interact
with their friends in ways that weren’t possible before. Playing games
6
with your friends, comparing scores on quizzes, and throwing sheep
at old high school buddies, are replacing traditional avenues of com-
munication, like email.
It is important to realize that Facebook is replacing other forms of
entertainment. Facebook is a place where people come to play. Apps
that do well on Facebook are those that facilitate social interaction. A
clone of an offce application, like Microsoft Word for instance, would
not do well on the platform.
Social Data
Many applications can be built simply based on knowing who a per-
son’s friends are. But most of the data you see on a person’s profle
can be used as part of your app. Facebook does not allow you to
store any user data besides user IDs, but you can incorporate user
data in real-time in your app. For instance, Video Jukebox (http://apps.
facebook.com/jookbox) scans your favorite music to fnd music videos on
YouTube, and allows you to embed them on your profle.
7
The Facebook Platform
chapter 2
A Facebook web application is hosted on your own server, just like a
regular Rails application. The application runs within Facebook, but
requests are proxied via Facebook to your server. The diagram below
illustrates this interaction:
the FaceBooK reQUest/response seQUence
CET h11p.//apps.1acebook.com/myapp/useJ/1
User
f
FaceBooK raILs app
Cahvas bRL
CET h11p.//myapp.com/useJ/1
Caììback bRL
f
FaceBooK
P0ST h11p.//ap1.1acebook.com
Soc1aì 0a1a {XhL/JS0h)
raILs app
Coh1eh1 {hThL + FBhL)
f
FaceBooK User
Coh1eh1 + RehdeJed FBhL {hThL)

8
All Facebook API responses have extra Facebook-specifc parameters
appended to them. These parameters contain information that will
subsequently be used to communicate with the Facebook API.
note Every Facebook API request is a POST
The Facebook Platform also allows you to create desktop applications
that make use of Facebook’s social data. However, since we’re talk-
ing about Rails and Facebook, this book will only cover how to make
Facebook web applications.
The Facebook API
The Facebook API is a REST web service that makes available social
data about users, and allows you to publish back to Facebook. The
API is documented at the wiki (http://wiki.developers.facebook.com/index.php/
Main_Page). Luckily, we do not have to use this API or parse the XML
responses manually. Using a Ruby library like Facebooker (https://ruby-
forge.org/projects/facebooker) can greatly simplify the task of developing a
Facebook application.
FBML
FBML is an HTML-like language developed by Facebook to make view
development easier and help your app conform to the look and feel
of Facebook. FBML also provides many convenience tags to do com-
mon tasks like displaying user names and constructing friend selec-
tors. Some Ruby libraries, such as Facebooker, provide Rails helpers
that wrap FBML tags to make the development experience more
Rails-like, and absolve the developers from learning the HTML-like
FBML syntax, which Rails developers have long forgotten by now.
9
Tags
The countless FBML tags are all described on the developers wiki
(http://wiki.developers.facebook.com/index.php/FBML). Probably the most useful
tags provided by the platform are the ones that allow an application
to render a person’s name and/or profle picture while only supplying
the ID of the person. This is particularly useful when displaying infor-
mation about Friends of the application users. Here is list of some of
the more useful helper methods:
fb_name(uid, options) • With this tag you can not only render
the users name but also make it possessive, refexive and linked to
the user’s profle
fb_pronoun(uid, options) • This also allows for the possessive,
refexive and objective forms of the pronoun
fb_profle_pic(uid, options) • You can control the size of the
profle thumbnail and make it a link to the user’s profle
fb_comments(comment_id, options) • This allows the application
to provide a comment section without having to store any of the
data
fb_error(message) • Displays a Facebook-styled error message;
there are also explanation and success messages
note There are many tags that can be useful in different contexts.
Some provide fow control, others are for specifc facebook
features and still others are used to embed media content
Forms
Standard rails helpers for web forms work as expected on Facebook
Canvas pages. However, there is a special form helper to render a
Facebook-styled form, called an editor. This set of helpers ends up
rendering custom <fb:editor*> FBML tags. There are, however, a
10
couple of gotchas with this form helper. The frst is that the form is
rendered in a table and as such it can be diffcult to style it in certain
ways. The second is that the FBML parser seems to strip out under-
scores from the names of the feld elements. So text_feld(:users_
friend, :name) will show up as params[:usersfriend][:name] .
Here is an example of a facebook_form_for call:
editor.rhtml
<% facebook_form_for(:poke,@poke,:url => create_poke_path) do |f| %>
<%= f.text_field :message, :label=>”message” %>
<%= f.buttons “Save Poke” %>
<% end %>
FBJS
Overview
FBJS is Facebook’s approach to allowing developers to use Javascript
in their applications. Instead of forcing developers to use IFrames for
all their dynamic content, Facebook creates a Javascript Sandbox by
limiting the abilities of the Javascript Environment, parsing all appli-
cation Javascript, and scoping the methods and variables by prefx-
ing variable names with the application ID. Also, note that all DOM IDs
get changed in this way as well. For example:
function foo(bar) {
var obj = {property: bar};
return obj.property;
}
becomes
function a12345_foo(a12345_bar) {
11
var a12345_obj = {property: a12345_bar};
return a12345_obj.property;
}
A call to it would end up looking like:
var a12345_result = a12345_foo(“some_thing”)
Facebook also changes many of the core Javascript methods used
for inspecting and interacting with the DOM. The entire list can be
found on the wiki at FBJS—Facebook Developers Wiki (http://wiki.develop-
ers.facebook.com/index.php/FBJS). Many of these method changes involve
simply adding the prefx get to the method name. So className
becomes getClassName and id becomes getId, etc.
Third-Party Libraries
Because of the way Facebook parses all incoming Javascript, third-
party Javascript libraries do not work within Facebook FBML pages.
Facebooker developers have started re-creating pieces of the Pro-
totype codebase in order to more easily support some of the Rails
Javascript Helper methods, most notably the Ajax helper methods.
This is a moving target in the Facebooker codebase and as of this
writing $(‘element_id’) and link_to_remote and remote_forms
are working when passing a DOM ID to update. RJS is not working
and may not be able to work due to the absence of the eval method.
AJAX
Facebook has two kinds of support for AJAX, Mock AJAX and the
Local Proxy. When using Mock AJAX, Facebook makes the call to
your server on the browser’s behalf and the response then goes
12
through Facebook, gets processed the same as all requests, and
returns to the Javascript callback. The callback can then either
process JSON results or insert FBML by calling $(‘updated_div’).
setInnerFBML(data). When using the Local Proxy, you may opt
to send requests directly to your server, but in this case you cannot
use any of the Facebook FBML tags in your response since Facebook
will not have the opportunity to parse them before they reach the
browser. This Local Proxy method uses a Flash Hack and requires
that the Flash Plugin be installed. Refer to the wiki, FBJS_LocalProxy
(http://wiki.developers.facebook.com/index.php/FBJS_LocalProxy) for complete
setup details. Currently Facebooker does not have helper methods for
the LocalProxy so you will have to roll your own AJAX.
The current Facebooker implementation for link_to_remote does
not support javascript methods being called after the request has
completed, so Ruby Footprints rolls its own Ajax call using Mock Ajax.
It also uses the FBJS Dialog class to create a confrmation dialog
that will eventually fre off the request. Here is the code from Ruby
Footprints that grabs the friend ID to step on and sends it as an AJAX
request. After the request is complete it does some animation to
notify the user what was accomplished.
function submitForm(varForm, url, div_id){
try {
//Grab the friend ID from the FORM
name = varForm.serialize().friend_selector_name;
friend_uid = parseInt(varForm.serialize().friend_to_step_on);
if( friend_uid == undefined || friend_uid == 0 || isNaN(friend_uid) || name.length == 0) throw
RangeError;

//Confirmation Dialog sends request on Confirm
dlg = new Dialog();
dlg.showChoice(‘Confirm Request’, “Are you sure you want to step on “ + name + “?” , ‘Yes’,
‘No’);
dlg.onconfirm = function() {
var ajax = new Ajax();
ajax.responseType = Ajax.FBML;
13
ajax.ondone = function(data) {
// Replace FBML
$(div_id).setInnerFBML(data);
//Animate the updated div.
obscure(highlight(revealDiv(div_id).checkpoint()).checkpoint()).go();
};
ajax.post(url, varForm.serialize());
}
}
catch(err) {
new Dialog().showMessage(“Error”,”Something weird happened. Did you type in a friend?”);
}
return false;
}
note The obscure, revealDiv and highlight methods are
provided in the application.js fle and are not directly a part
of FBJS.
Animation Library
Facebook has actually released their animation library and, while it
lacks the breadth of features of Scriptaculous, it does have a nice
approach to animation by using method chaining. Here is a high-
lighting animation example from Ruby Footprints:
Animation(document.getElementById(div_id).to(‘background’, ‘#FF00FF’).duration(2000).checkpoint().
to(‘background’, ‘#F7F7F7’)
The library uses tweening of CSS attributes in order to get the job
done. The above example takes 2 seconds to change the background
to purple, stops for an instant, and then restores the background to
Facebook’s standard grey. The library also provides support for hid-
14
ing and showing elements, moving elements, and both default and
custom ease functions. For a complete description, refer to the wiki at:
FBJS/Animation. (http://wiki.developers.facebook.com/index.php/FBJS/Animation).
15
Getting Started
chapter 3
Facebook Signup
The way you manage your Facebook applications is through an
application created by Facebook called Developer. Install the app by
logging into Facebook, going to the Get Started Page (http://developers.
facebook.com/get_started.php), and clicking Add Facebook Developer Appli-
cation (http://www.facebook.com/developers). After you have this applica-
tion installed you can create a new application by clicking the ‘Setup
New Application’ button. This will produce a form page on which to
submit your application settings. The settings for Ruby Footprints are
included at the end of each step.
16
Application Name: It seems
that this does not need to be
unique across all Facebook
apps.
Callback URL: This is the URL
of the server hosting your
application. Facebooker
assumes that this URL will
resolve to the document root of
your application. Make sure you
have the trailing slash on the
end and also put this value in
your facebooker.yml fle under
RAILS_ROOT/confg.
Canvas Page URL:
This must be unique
across all Facebook
applications and will be
visible to your users in
the location bar of the
browser. Put the value
that you choose into
your facebooker.yml fle.
Can your application
be added on
Facebook? After
selecting YES here
you will be prompted
with another list of
options.
TOS URL: Enter in your Terms of
Service URL. This will show up
as a link on your add application
page and must either go to an
external page or a page that is
not authenticated to Facebook.

17
Scrolling down, you will fnd Installation options for your application.
Check the Users box for 'Who
can add your application'
Post-Add URL: This is
the URL that gets
called after a user adds
your application. It is
best to simply use your
Canvas Page URL:
http://
apps.facebook.com/
ruby_footprints
Developer Mode:
Check this box to make
sure that other users
cannot add your
application.
Default FBML, Default Action,
and Default Profile Box Column
are discussed in the Profle
section below. You can leave
them blank for now.
Application Description: This
description will be shown to users
when they are given a choice to add
your application. It will also appear
on the Application About Page and in
the Application Directory. Make it
enticing so people will add your
application.

Next you will confgure various integration points for your application.
18
Side Nav URL: This is a very
important integration point as
it will result in an icon and link
on the left of the user's profle.
It must go to a Canvas Page.
Help URL: This can be an
external URL, a Facebook
Canvas page that shows help,
or a FAQ for your application.
Privacy URL: This will
create a link that the
user will see when
editing the application
privacy settings. It
should be a Facebook
Canvas page.
Private Installation:
This will prevent news
stories from being
published by your
application, and is a
good idea during
development.

19
After you save your application settings you will be taken to a sum-
mary page that will have your API and Secret keys. Take these keys
and place them into your facebooker.yml fle. The Ruby Footprints
facebooker.yml fle looks like this:
development:
api_key: 921628d9d70f5e0b5887936802abe9e6
secret_key: 77sEcRETsecretSECRET3ce96c
canvas_page_name: ruby_footprints
callback_url: http://rfootprints.shacknet.nu
Facebooker
Facebooker is our Facebook library of choice. Facebooker goes to
great lengths to abstract the XML-based Facebook API calls, so you
only have to be aware of pure Ruby objects. Facebooker can be used
as a gem or a Rails plugin. I prefer to use it as a plugin, as it takes
care of all the initialization needed to integrate the Facebook API with
Rails.
Facebooker has recently moved the primary repository over to GitHub
and you can install it in a few ways. If you are on Rails 2.1 and have
installed git, you can use script/plugin:
script/plugin install git://github.com/mmangino/facebooker.git
If you are on an older version of Rails but still have git installed, you
can clone it to the vendor/plugins directory.
cd vendor/plugins
git clone git://github.com/mmangino/facebooker.git
20
Or, download the source directly from GitHub (http://github.com/mmang-
ino/facebooker) and unpack it into your vendor/plugins directory.
note Preferably we would be able to use Piston to manage this
plugin, but it does not currently support git. There are some
workarounds but the Rails community hasn’t really settled on
the correct approach yet.
Facebooker does its best to make Facebook app development as
close to regular Rails app development as possible. The plugin mon-
keypatches Rails controllers to include everything you need to access
Facebook, via the facebook_session method.
Configuration
First, generate a basic facebooker.yml confguration fle using:
rake facebooker:setup
Fill in your server info appropriately. For example, if your public server
is shanesbrain.net and it has port 4007 free, then facebooker.yml
will look like:
development:
tunnel:
public_host_username: shane
public_host: shanesbrain.net
public_port: 4007
local_port: 3000
21
Hello World
This simple application will print “Hello” followed by your frst name.
hello_world.rb
class Welcome < ApplicationController

def index
@first_name = facebook_session.user.first_name
end
end
Hello <%= @first_name %>
In order to test this, you will have to set up a development environ-
ment or deploy your application to Facebook.
Development Environment
Ideally, you want to be able to test your app as you develop, like
you would a normal Rails app. Simply running the Mongrel develop-
ment server will not suffce, since that will not route requests through
Facebook. Thankfully, the Ruby community is proud to include smart
people like Evan Weaver, who came up with a way to test Facebook
apps locally using a reverse SSH tunnel (http://blog.evanweaver.com/arti-
cles/2007/07/13/developing-a-facebook-app-locally). There is no need to worry
about the details of setting it up, as Facebooker provides rake tasks
for completing the setup. As long as you have a public facing server
with available ports, you can set up a reverse tunnel to your local
machine. Facebook will communicate with your public server as if it
were a normal Facebook app, while your server routes the requests to
your machine.
Start the tunnel with:
22
rake facebooker:tunnel:start
You may check the status of the tunnel with:
rake facebooker:tunnel:status
If you don’t have a public facing server with open ports, you can try a
service called Tunnlr (http://tunnlr.com).
[Tunnlr is] a forwarding service that you can use at home, at
Starbucks, or anywhere you have an Internet connection…
It securely connects a port on your local machine to an open
port on our public server. Once you start your Tunnlr client,
the web server on your local machine will be available to
the rest of the world through your special Tunnlr URL.
23
Facebook Authentication
chapter 4
The Facebook API uses a shared secret called the secret_key to
authenticate all communications between your application and the
Facebook API. It is implemented by concatenating all the request
parameters together with the secret_key and running a hashing func-
tion on the result. Facebooker gives your application high level access
to the authentication and permissions mechanisms provided by the
Facebook Platform.
Verifying Request
Even if your application does not require any special permissions
from its users, it is still a good idea to verify that the incoming request
has not been tampered with. To accomplish this add a before flter for
set_facebook_session to your ApplicationController. This call
will raise an Exception if the request is not valid. After a successful
call to set_facebook_session the instance variable @facebook_
session will be set and session[:facebook_session] will be stored.
note Facebooker overrides the rails Session Key in order to retain
a session across requests for Facebook users. The call to
set_facebook_session will look into session[:facebook_
session] in order to see if there is already a session object
available.
Authenticating a User
In order for your application to take action on the behalf of a user or
to gain extra permissions, Facebook will issue a session key for that
24
user. These actions can include posting to a news feed or sending
notifcations and there are currently two types of session keys, infnite
and expirable. An Application can request a session key in one of two
ways, by sending the user to the Application Login page or sending
the user to the Application Add page. Facebooker supports both of
these through class level calls available in the controller; both of these
calls take the same options as before_flter.
The ensure_authenticated_to_facebook method will attempt to
validate the Facebook parameters and on failure will redirect the user
to the Login URL. At this URL the user will basically be asked whether
they want to grant an infnite session key or a session key that will
expire.
The ensure_application_is_installed_by_facebook_user
method will validate the Facebook parameters and check to see if the
the parameter indicating that the user has added the application is
set. Most applications will require that the user add the application as
it not only can give the application more permissions but it also will
publish the choice to the user’s news feed.
By default after a user adds the application Facebook will redirect
the user to the Post Add URL that was setup in the developer app.
In some cases this is not ideal, however. Overriding this behavior
is supported by the Facebook API, although currently Facebooker
doesn’t give easy access to changing this. In order to send your users
to some other URL you will need to override the controller method
application_is_not_installed_by_facebook_user and pass in a
:next parameter to the install_url. Here is an example from Ruby
Footprints:
ruby_footprints/app/controllers/application.rb
def application_is_not_installed_by_facebook_user
redirect_to session[:facebook_session].install_url(:next => next_path() )
end
25
private
def next_path
non_keys = [ “method”, “format”, “_method”, “auth_token”]
url_hash = {}
params.each do |k,v|
next if non_keys.include?(k.to_s) || k.to_s.match(/^fb/)
url_hash[k] = v
end
url_hash[:only_path] = true
url_hash[:canvas] = false
url_for(url_hash)

end
note There is surely a cleaner way to create a URL from the request
parameters. Please do investigate.
26
Getting Social Data
chapter 5
User and Friend Data
You can access nearly all the data that is public on a user’s profle
once he or she installs your application. You may use this data in
your application, but Facebook has limits on what you may store
persistently. You can generally store numerical identifers such as user
IDs (UIDs) and photo IDs (PIDs), but nothing more. It is also illegal to
store friend relationship id pairs, such as <uid, uid>. Refer to the
developer documentation (http://wiki.developers.facebook.com/index.php/Main_
Page) for storage guidelines.
For example, here is how to fetch a user’s favorite music:
facebook_session.user.populate(:music)
music = facebook_session.user.music
Assuming the user has a comma-separated list of artists, you can
split the string to get each artist. You can use a similar approach to
get any number of user data, including activities, interests, favorite
movies, etc. See the sidebar for a complete list.
Photos
Facebook organizes photos into albums, and each photo has its own
photo id (pid). You can specify either a list of photo IDs, an album id,
or a subject id. The subject id is the UID of a specifc user. Specifying
the subject id will retrieve all the photos in which the particular user
was tagged.
complete list of user data
The facebook_session.user.populate()
method accepts one or more of the following
symbols. Leave blank to get them all.
:status, :political, :pic_small,
:name, :quotes, :is_app_user, :tv,
:profile_update_time, :meeting_sex,
:hs_info, :timezone, :relationship_
status, :hometown_location, :about_
me, :wall_count, :significant_
other_id, :pic_big, :music, :uid,
:work_history, :sex, :religion,
:notes_count, :activities, :pic_
square, :movies, :has_added_app,
:education_history, :birthday,
:first_name, :meeting_for, :last_
name, :interests, :current_location,
:pic, :books, :affiliations
All of the above return String values, except
for location, high school info, status,
affliation, education info, and work info.
These return their own model objects that have
accessors for their attributes. For example:
location_example.rb
facebook_session.user(:location)
# => Location object
location.city
# => Chicago
27
Facebooker includes a few convenience methods for common photo
tasks:
facebook_session.user.albums •
facebook_session.user.profle_photos •
The albums method retrieves a list of album IDs (aids) for the cur-
rently logged in user. These can be plugged into facebook_session.
get_photos to get the photos for each album. Note that pid, subj_id,
or aid must be supplied to facebook_session.get_photos. For
example, all the incriminating photos for user 12345 can be retrieved
with facebook_session.get_photos(:subj_id => 12345).
Facebook has a special album for profle photos, which cannot be
retrieved using the method above. You need to do some trickery
involving complex mathematics to get this album. Luckily, the smart
developers of Facebooker have abstracted the complexity with the
profle_photos method. It simply retrieves all the profle photos for
the currently logged in user.
Events
Facebooker provides a convenience method to get the events for a
user. You can flter events by start time, end time, and RSVP status.
The following returns the events between now and a month from now:
@user.events(:start_time => Time.now.to_i, :end_time => 1.month.from_now.to_i)
Once you have a list of Event objects, you can access the attributes
of each Event, such as description, venue, host, location, etc.
28
Anatomy of an App
chapter 6
Integration Points
Your main application runs inside a Facebook canvas page, but Face-
book allows additional means to interact with, promote, or advertise
an action of your application. Your application is entitled to its own
box on a user’s Facebook profle page. The content of this box can be
rendered differently based on whether users are viewing their friends’
profles or their own. You also have the option of adding a link under
the user’s profle picture.
Feed items (not to be confused with RSS/Atom feeds) are little blocks
of content that you publish based on actions taken in your applica-
tion. For example, if you have an application that spanks a friend,
then it can publish a feed story informing the user and his or her
friends about the spank. Now don’t get the bright idea to make a
spanking application, as it has already been done, and no, not by
me. There are two types of feed items, the News Feed and Mini-Feed.
The News Feed contains stories about all your friends’ activities while
the Mini-Feed is only for activities that are either initiated by you, or
involve you in some way (for example, if someone tagged a photo of
you).
Facebook has two types of notifcations that are meant to serve as
individual communication between the application and the user. Reg-
ular notifcations go to the user’s notifcation page, which is accessed
by a link in the right sidebar on the Facebook homepage if the user
is logged in. This page contains information that Facebook considers
relevant yet not important enough to go into the user’s News Feed.
The other type of notifcation is email notifcations. As expected this
sends an email to the user on behalf of your application, as long as
29
their privacy settings are set to allow it.
Facebook also has hooks to allow your application content to be
included in wall and message attachments.
Summary of Integration Points
facebook home page
Message Inbox •
Notifcations •
Status Updates •
News feed •
Requests •
profile page
Narrow box on left side, under picture •
Link under profle picture (this is not available in the new Facebook •
layout)
tabs
Boxes tab: Narrow or Wide profle box •
Application tab •
Info tab box •
Wall (previously called the Mini-Feed in the old layout) •
Status update •
email
Attachments •
Share messages •
30
other
Application description and image in the Application Directory •
Application reviews and discussions in your About page •
On all pages, your application can be shown on the Sidebar applica-
tion list if the user allows it.
Overall, you have quite a few choices for integrating your application
tightly with Facebook to create a seamless user experience.
The Profile Page
The Profle Page on Facebook provides a space for your application
to have a presence. This space involves a few restrictions.
The user must add your application and grant permission to your •
application
The content must be explicitly published to the profle through the •
Facebook API
You can use • FBJS but it will not run until the user clicks on the
space, and it cannot communicate with your server
The content is restricted to one of two widths: narrow or wide •

There are two main
parts of a user’s
Profle, the Profle
Action and the
Profle FBML. The
Profle Action is
simply a link that goes below a user’s profle picture. The Profle FBML
31
is a piece of FBML that allows a user and the user’s friends to see
what the user has been doing with your application. The Ruby Foot-
prints Application shows a tally of the number of times the user has
stepped on and been stepped on. The Profle Action, if you set it up
correctly, shows up as a link below every profle that your user looks
at (see Profle Wiki link (http://wiki.developers.facebook.com/index.php/Profile)).

Both the Profle FBML and the Profle
Action can have defaults set for the appli-
cation. Many apps will setup the Default
FBML to simply contain an fb:ref tag. This
way the content can be updated for all
users of the app with one request. By
setting the default Profle Action for your
application you actually gain something
very powerful. The link will appear under
the profle for every profle your application
users view, not just the profles of people
who have added the application. You can
set both defaults in the application settings
page. Here is the default Profle Action for
Ruby Footprints:
<fb:profile-action url=”http://apps.facebook.com/ruby_footprints/step/on”>
Step On <fb:name uid=profileowner firstnameonly=”true”/>
</fb:profile-action>
There are a couple of ways in Facebooker to publish to a user’s Pro-
fle. The simplest way is through methods directly on an instance of a
Facebooker::User. Its available methods are:
publish_profile.rb
32
@facebooker_user.profile_fbml = “A string of FBML”
@facebooker_user.mobile_fbml = “A string of FBML for mobile profile”
@facebooker_user.profile_action = ‘<fb:profile-action url=”http://www.mysite.com/action/”> Perform
Action </fb:profile-action>’
@facebook_user.profile_main = “FBML for a Profile Box on the Main Profile”
@facebook_user.set_profile_fbml(profile_fbml, mobile_fbml, profile_action)
These methods are of limited use since you will have to code up the
FBML manually or hack in your own template rendering.
The preferred method of managing a user’s Profle page is through
what we will call the Publisher API. Facebooker::Publisher uses a simi-
lar approach to ActionMailer and it allows you to render templates
and to use helper methods to create your FBML. The Publisher API
currently supports sending Feed Stories, Notifcations and Emails, set-
ting a user’s Profle, and setting FBML reference handles. Here are the
basic steps to creating a Publisher:
Run the Publisher generator • ruby script/generate Pub-
lisher Facebook. This will create a class that extends
Facebooker::Publisher.
Defne a method with any number of arguments and call it what- •
ever you would like, as long as it does not confict with other
instance methods.
In that method call the method • send_as with the type of thing you
are publishing. Available choices are :profle, :email, :notifca-
tion, :story, :action, :templatized_action, and :ref.
Call • FacebookPublisher.deliver_<method_name>(*args).
Here is an example from Ruby Footprints of setting the user’s Profle
FBML and Profle Action using the Publisher API:
ruby_footprints/app/models/facebook_publisher.rb
def profile_for_user(user_to_update)
33
send_as :profile
from user_to_update.facebooker_user
recipients user_to_update.facebooker_user
fbml = render({
:partial =>”/footprints/user_profile.fbml.erb”,
:locals => {:user => user_to_update}
})
profile(fbml)
profile_main(fbml)
action = render(:partial => “/footprints/profile_action.fbml.erb”)
profile_action(action)
end
note The above example calls the recipients method, which might
seem a little strange but the Facebook API allows you to set the
Profle for any of your users using a single session key.
With Facebook’s New Profle Design, an application’s Profle Box
can live in one of two places, inside the Boxes Tab and on the
Main Profle Page. An application will need to ask a User to explic-
itly request the applications presence in one of these places. This
request is handled via a custom FBML tag, <fb:add-section-button
section=”profle” />. If you notice in the example above, the pub-
lisher code calls both profle and profle_main. The call to profle
will set the profle FBML for the Boxes Tab while profle_main will set
the FBML for the user’s Main Profle.
note The Profle Action link has been deprecated by Facebook and
will not be available in their next release of the Platform. This
change is corresponding with the fnal edits of this book so
we decided to leave it in just in case you see references to it
elsewhere.
34
New Profile Application Tab
The new Facebook Profle design gives applications a new integration
point. Your application can get access to some coveted real estate
on the user’s profle. Instead of there being application profle boxes
on the main user profle, users will have to select applications that
they would like to highlight on their own profles. To give your users
access to this tab you confgure both the Profle Tab URL and Profle
Tab Name in the application settings. The Profle Tab URL is a canvas
page URL and there a few differences with this FBML canvas:
You cannot use IFrames •
The session key that you get is a temporary key and is different •
from the user’s infnite session key, it is also a read-only
It doesn’t know who the viewing user is •
Flash and Javascript have the same restrictions as the Profle Box •
Once your application is setup to support the Profle Tab, when a user
loads that particular tab Facebook will call the Profle Tab URL. You
can add dynamic interaction with the Tab via AJAX; however, all HREF
links will go to your canvas page.
note Since this feature is so new it is likely to change as users and
application developers interact with it. Check the wiki under
Tabbed Profle (http://wiki.developers.facebook.com/index.php/New_Design_
Tabbed_Profile) for the latest information.
News Feed and Wall
There are three different ways to publish stories to a user’s feeds.
Each way gives you access to either the Wall or News Feed or both.
You also get the ability to publish stories to friends that have not
35
added your application. This last feature may sound very appealing
for its possibilities of rapidly propagating your application; don’t get
your hopes up too high, though, as Facebook’s standards appear to
be very restrictive for this type of messaging. The table below shows
the difference between each method:
Feed Action Story TemplatizedAction
Wall Yes No Yes
News Feed Friends’ with app Own All Friends’
Usage Limits 10 times every 48 hours once every 12 hours 10 times every 48 hours
Facebooker exposes each of these API calls via the Publisher API, as
introduced above.
Publishing Stories
In the Ruby Footprints example application we decided to nudge
users back to the application by notifying them once a day of their
friends’ activities. Many applications have some sort of visual compo-
nent, perhaps a photo or an icon of a gift. For Ruby Footprints we will
include our Ruby Footprints logo to add some fare to the feed story.
ruby_footprints/app/models/facebook_publisher.rb
def nudge_story(user)
send_as :story
recipients(Array(user.facebooker_user))
db_friends = FacebookUser.find_friends(user.friends)
if( db_friends.blank? )
title = “None of your friends stepping on people!!”
else
title = db_friends[0..3].compact.collect{ |friend|
fb_name(friend.uid)
}.to_sentence + “ have been stepping on people.”
36
end
body = “Get <a href=’#{footprints_url}’> stepping </a> on your friends.”
body = body[0..200] if body.length > 200
self.body( body )
self.title( title )
image_1(image_path(“tiny-footprint.png”))
image_1_link(footprints_url())
end
note There are limits on your title and body length, excluding tags, so
if these are generated dynamically make sure to truncate them,
otherwise you will get an error from Facebook.
Publishing Templatized Actions
Publishing a templatized action adds some complexity to the pro-
cess. The reason behind this is aggregation. In order for Facebook to
increase the quality of News Feed items, they attempt to aggregate
similar stories into a single item on the News Feed. This is a good
thing for developers as it gives you more of a chance for your story
to appear on the News Feeds of friends. The more stories you pub-
lish, in theory, the more of a chance you have of your aggregated
story getting published. In general the body_template, body_data,
title_template, title_data, and target need to be identical for
a story to be aggregated. So the story “David stepped on Shane”
can become “David and Doug stepped on Shane”, but only if we both
stepped on Shane. You should defnitely read up on the wiki (http://wiki.
developers.facebook.com/index.php/Feed.publishTemplatizedAction) to understand
better how aggregation works; it can be very powerful. And notice
that you will need to go through the steps of registering the templates
before you can take advantage of the aggregation.
37
Here is Ruby Footprints method from your FacebookPublisher class:
ruby_footprints/app/models/facebook_publisher.rb
def footprint_feed_item(attacker, victim)
send_as :templatized_action
from(attacker)
title_template “{actor} stepped on {target}”
target_ids([victim.id])
body_general(“Check out #{link_to(“#{fb_name(victim, :possessive => true)} Ruby Footprints”, new_
footprint_url(:friend_to_step_on => victim.id )) } “)
image_1(image_path(“tiny-footprint.png”))
image_1_link(footprints_url())
end
And here is what it will look like in the Mini-Feed and (if you are lucky)
the News Feed:
note The call to target_ids is a specifc parameter for these types
of actions. Facebook will use these IDs in order to aggregate
stories from many different users.
Publishing Actions
Publishing Actions is very similar to publishing Stories; in fact the
Facebooker::Feed::Action class is a duplicate of the Story class.
Actions, like stories, have a title, a body, and images. Since we are
38
using Templatized Actions in Ruby Footprints we don’t really have any
use for regular actions. Here is some example code; notice that it is
very similar to the code for sending a Story.
ruby_footprints/app/models/facebook_publisher.rb
def example_action(user)
send_as :action
from( user)
title “just learned how to send a Mini-Feed Story using Facebooker.”
body “#{fb_name(user)} just checked out #{link_to(“Ruby Footprints”, footprints_url)}. A Ruby based
Facebook example application.”
image_1(image_path(“tiny-footprint.png”))
image_1_link(footprints_url())
end
note Not only can you use helper methods in there, like fb_name, but
you can call render :partial => ‘/some/partial’.
The New Facebook Feed Story Format
Sometime in the Summer of 2008 Facebook will fnally release its
new Profle design and with that comes a new format for News Feed
Items. The purpose of this new format is to give users a greater
amount of control over their personal profle pages. Users will be
given control over how Mini-Feed stories appear on their profles and
application developers will have some work to do in order to support
this greater level of control.
Mini-Feed stories will now support three different lengths of stories,
one-line, short, and full. The API requires that you register these sto-
ries before using them and the nice thing is that registering is built
into the API and Facebooker supports it. When generating a new
Publisher, Facebooker will create a database migration to store all the
needed template IDs since a template ID is required to publish feed
39
stories. Your Publisher works very much the same way as the Pub-
lishTemplatizedAction feed stories, only it also need to support
the registering of the templates. Here are the steps:
Create a method that describes your template. Call it something •
like mini_feed_template (it must end in template)
Describe the template with three methods: • one_line_story_tem-
plate, short_story_template(title, body), and full_story_
template(title, body)
Create a method for delivering the feed story in the same way that •
TemplatizedActions are supported. It must start with the same pre-
fx as your template method. e.g. def mini_feed
Call • send_as :user_action, from(user), and data(hash_of_
data_to_populate_the_template) inside the delivery method
Call • FacebookPublisher.register_mini_feed at some point
during the fow of your app
And here is an example from the Ruby Footprints application.
ruby_footprints/app/models/facebook_publisher.rb
def new_footprint_feed_item_template
one_line_story_template(“{*actor*} stepped on {*target*}”)
short_story_template(“{*actor*} stepped on {*target*}”, “You can {*general_step_link*} on people
too! With Ruby Footprints.” )
full_story_template(“{*actor*} stepped on {*target*}”, “{*image_link*} <p>Don’t let them get away
with treating each other this way.</p><p> {*call_to_action*}</p>”)
end
def new_footprint_feed_item(footprint)
victim = Facebooker::User.new(footprint.victim.uid)
attacker = Facebooker::User.new(footprint.attacker.uid)
send_as :user_action
from(attacker)
target_ids([victim.id])
data({
:general_step_link => link_to(“Step”, footprints_url) ,
40
:image_link => link_to(image_tag(“tiny-footprint.png”), footprints_url),
:call_to_action => “Check out #{link_to(“#{fb_name(victim, :possessive => true)} Ruby
Footprints”, new_footprint_url(:friend_to_step_on => victim.id )) } “
})
end
note The place holders for template data have a different format than
they did with the TemplatizedAction templates. The key is
surrounded by asterisks, as in the example above.
Notifications
Notifcations are generally shorter than feed items and do not con-
tain any images. They are handled by the Publisher API and simply
have a sender, recipients and a block of FBML. A Notifcation can be
a great way to spread your application by notifying friends that a
user has taken some action that involves them. Ruby Footprints uses
notifcations to let other users know that they have been stepped on
so that they can retaliate and do some stepping on their own.
ruby_footprints/app/models/facebook_publisher.rb
def footprint_created(footprint)
send_as :notification
victim = Facebooker::User.new(footprint.victim.uid)
attacker = Facebooker::User.new(footprint.attacker.uid)
# Note this only works during a request cycle
# since the session is being held for us
self.recipients(victim)
self.from(attacker)
fbml “ stepped on you. #{link_to(“See all your Ruby Footprints” , footprints_url) } “
end
41
note One thing to note is that when you send a notifcation to a user
on another user’s behalf, the sender will also get a notifcation
that they sent something, so be careful not to abuse the system,
or your users will know and punish you for it.
Emails
Your application can send emails to users who have added the
application. The email can contain both a text version and an HTML
version. Do not try to do anything fancy though, because the set
of allowed tags is limited to tags that result in text only. The email
actually appears to come from your application so you cannot send
emails from one of your users to another; that is what notifcations
are for.
ruby_footprints/app/models/facebook_publisher.rb
def example_email(from,to, title, text, html)
send_as :email
recipients(to)
from(from)
title(title)
fbml(html)
text(text)
42
end
Like notifcations, the limit on emails is calculated per application,
and once again a big part of that calculation is user feedback. The
email itself will have a link for your users to click in order to block your
application from sending any more emails, so be kind. See the side-
bar for details on allocation limits.
note If your notifcations or emails fail, make sure that you are not
sending any markup other than text and links. Facebook will
happily drop your notifcation on the foor and give you a
successful response. Start simple.
Invitations
Invitations in Facebook are another way for your users to interact with
each other. Invitations differ from previously mentioned ways of com-
municating with users in that they must be specifcally initiated by a
user. Probably the most common invitation is a request to install an
application. Some applications go so far as to require users to do this
in order to unlock certain functionality, while others will offer additional
points or benefts based on the number of friends that get invited.
The Invitation is handled through a few specifc FBML tags and Face-
booker has methods for each of those. Here are all the pieces you will
need to put this together:
Text for the call to action button on the invite itself •
Text for the send button •
URL • for the recipient to click on
URL • to go to after sending the Invitations. This request will include
the IDs of the invite users and can be used for tracking purposes
43
Call to action text for user sending the Invitations •
Ruby Footprints gently encourages users to pass the word by pro-
viding a link at the bottom right of the layout. This link renders the
following FBML:
ruby_footprints/app/views/admin/invite_friends.fbml.erb
<% content_for(“invite_user”) do %>
Check out Ruby Footprints.
It is an example Facebook app built with Ruby.
<%= fb_req_choice(“Check it out!”, friend_footprints_url()) %>
<% end %>
<% fb_request_form(“Ruby Footprints”,
“invite_user”,
invited_friends_url()) do %>
<%= fb_multi_friend_selector(“Invite your friends to check out Ruby Footprints.”,
:showborder => true,
:exclude_ids => current_user.friends_with_this_app.map(&:id).join(“,”)) %>
<% end %>
The frst part of this template sets up the content for the Invitation
itself. This is what the recipient will see. The call to content_for basi-
cally assigns the FBML from the block to an instance variable to be
later used by the request form. The name passed into this method
is the same name that is passed into fb_request_form. The con-
tent includes an fb_req_choice tag which renders the button to be
clicked by the recipient of the invitation and includes the URL that the
user will go to when called to action.
Next we have the friend selection form, accessible with the
fb:request-form tag as shown at the wiki (http://wiki.developers.facebook.
com/index.php/Fb:request-form). Familiarize yourself with all the different
permutations, as they can be useful in different circumstances. The
request form takes a String for the button the user clicks once all
the friends are selected, and a URL to go to after the Invitations are
44
sent out. This callback URL will contain the IDs of the users that were
selected. Ruby Footprints simply stores the IDs in the session to be
used in a fash message.
The request form takes a block and this block needs to render one
of the many Facebook friend selector widgets. Ruby Footprints is
using the multi friend selector, which is rather menacing, but popular
among applications. You will notice, if you play with Ruby Footprints,
that there is an indication on the form indicating how many people
can be invited. This number is one of the allocation limits that your
application is governed by and is a per day limit.
45
Info Section
In the New Facebook Profle, applications have the ability to provide
lists of data that users can embed into the Info Tab on their Profles.
This integration is done with an explicit action from the user clicking
on a button provided by a custom FBML tag, <fb:add-section-
button section=”info” />. Before the user clicks on this button
46
the application must publish some data to Facebook in a list format.
You can check out the wiki for all the details at Profle.setInfo (http://
wiki.developers.facebook.com/index.php/Profile.setInfo). The format of the JSON
data is an array of hashes with an array of hashes inside. This can be
a little tricky, so here is an example script that can be used to publish
this list data:
set_info_list.rb
require File.dirname(__FILE__) + ‘/../config/environment’
ENV[“FACEBOOKER_API”] = “new”
def footprints_info_list
[
{
:label => “Red Footprints”,
:link => “apps.facebook.com/rubyfoot_dev”,
:image => ActionController::Base.asset_host + “/images/tiny-footprint.png”
}
]
end
info_fields = [
{
:field => ‘Ruby Footprints’,
:items => footprints_info_list
}
]
FacebookUser.find(:all).each do |user|
user.set_profile_info(“Ruby Footprints”, info_fields)
end
New Profile Publisher
Facebook recently launched a new way to publish content, that aligns
with their new Publisher feature. Publisher (not to be confused with
Facebooker::Publisher) is a new tool that allows applications to
47
publish any kind of content to a user’s, or a user’s friend’s, Wall. This
is going to be an important integration point due to its prominence on
the user’s profle page. It is right at the top and sorted by most recent
activity. The Publisher is much more powerful than the Mini-Feed it
replaced. You can now publish FBML, Flash, or even load FBJS.
To begin using the Publisher, you need to specify an action and a
callback URL in the application settings.
There are two sets of actions and callback URLs, one for publishing to
your own profle and one for publishing to your friends’ profles. When
you have confgured the above, your application will show up in the
drop-down list near the Publisher bar on the Profle page, provided
the user has agreed to show it in your application’s Terms of Service:
48
Your application frst needs to render its own version of the Publisher
interface. Then it must generate the Feed story for the content to be
published.
Facebooker comes with support for Facebook’s Publisher. You frst
need to check if Facebook is requesting the interface for Publisher
by calling wants_interface? If true, you can render the form using
render_publisher_interface. This builds the JSON for the Pub-
lisher interface. If the interface has already been rendered, you
can publish the content using render_publisher_response. This
method takes in a UserAction object, which is provided by the
Facebooker::Publisher class.
Previously we discussed how to publish Feed Stories using the new
API provided by Facebook. The API and code for this new user-con-
trolled publishing uses the same mechanism and API as that used
to publish Feed Stories. First the application creates and registers a
template, then when asked the application returns the data for that
template. Ruby Footprints allows the user to publish his own stats to
his Wall; the controller logic is in AdminController, and the template
and template data are in the FacebookPublisher. Here is the con-
troller:
ruby_footprints/app/controllers/admin_controller.rb
def publish_self
user = FacebookUser.find_by_uid(params[:fb_sig_profile_user])
FacebookPublisher.register_publish_self unless
49
Facebooker::Rails::Publisher::FacebookTemplate.find_by_template_name(“publish_self_item”)
if wants_interface?
render_publisher_interface(render_to_string(:partial=>”/footprints/user_profile”, :locals =>
{:user => user}))
else
render_publisher_response(FacebookPublisher.create_publish_self(user))
end
end
This one action must respond to requests for the form that takes in
the user data and the request which returns the JSON-encoded data
for the template. In our case we are not actually requesting any form
data from the user, but typically this is what an application would
want to do. Notice that we check to see if the template has been
registered frst; this is not very effcient from a programming perspec-
tive but makes the example clearer. Now take a look at the template
defnition and the template data in the FacebookPublisher class.
ruby_footprints/app/models/facebook_publisher.rb
def publish_self_template
title = “{*actor*} Is a Ruby Footprint Master”
one_line_story_template(title)
short_story_template(title, “You can {*general_step_link*} on people too! With Ruby Footprints.” )
full_story_template(title, “{*fbml*}”)
end
def publish_self(user)
send_as :user_action
from(user)
data({
:general_step_link => link_to(“Step”, footprints_url),
:fbml => (render :partial => “/footprints/user_profile.fbml.erb”, :locals => {:user => user})
})
end
These defnitions work exactly like the defnitions used for publishing
50
Feed stories.
note In order to create the UserAction object we call
FacebookPublisher.create_publish_self. This is
another way the that Facebooker::Publisher is built around
the same concepts as ActionMailer.
51
programmatic configuration
Facebook continues to add more and more programmatic
access to confguration and application data. One of the
these that you can programmatically verify is the alloca-
tion limits put upon your application. There are allocation
limits for how many emails, notifcations and requests are
sent.
The limit on Notifcations is calculated per application, and
a big part of that calculation is user feedback. You can
check the current limit programatically and from within the
Developer application under Stats • Allocation. The initial
limit is 20 per day and Facebooker will raise an exception
after you have reached the limit. Check it by calling:
@facebook_session.admin.get_
allocation(:notifications_per_day)
Like Notifcations, the limit on Emails is calculated per
application, and once again a big part of that calculation is
user feedback. The email itself will have a link for you users
to click in order to block your application from sending
anymore emails, so be kind. If Facebook likes your applica-
tion it will put this disable link at the bottom of the email.
The initial limit is 5 per day and Facebooker will through an
exception after you have reached the limit. You can check
the limit by calling:
@facebook_session.admin.get_
allocation(:emails_per_day)
You can also see where the disable message is by calling:
@facebook_session.admin.get_allocation(:email_
disable_message_location)
A certain number of invitations can be sent from your
application per user per day. You will see this as a limit on
the friend selector widgets provided by Facebook. Check it
programmatically:
@facebook_session.admin.get_
allocation(:requests_per_day)
52
Testing
chapter 7
Functional tests
Testing Facebook apps is not much different from testing normal
Rails applications using the helpers that come with Facebooker. Unit
tests are pretty much the same as Rails tests. However, functional
tests require a little extra work since the Facebook parameters must
be appended to all requests. Luckily, facebooker comes with the
facebook_post method that replaces the normal post method that
comes with Rails. The facebook_post method will handle appending
the Facebook request parameters and generating the signature, so
you really do not have to know what is going on behind the scenes,
and can use facebook_post just as you would use post in a Rails
functional test.
Here is an example using all the test helper methods available with
Facebooker.
functional_test.rb
def test_create
assert_difference ‘Footprint.count’ do
facebook_post ‘create’, :id => 2
end
assert assigns(:stepped_on_user)
assert_facebook_redirect_to(‘http://apps.facebook.com/rubyfoot_test/’)
end
Actions that use the Facebook canvas use facebook_post to simu-
late a post to Facebook with the required parameters. Rails’ usual
assert_redirect does not work in the Facebook environment since
the request has to pass through Facebook’s server frst. Rather, a
53
Facebook redirect is a POST to Facebook with a special FBML redirect
tag. The assert_facebook_redirect_to test helper abstracts these
details for you.
Stubbing out the Facebook server
Often in functional tests, you would want to stub out calls to Face-
book so you will not have to make any calls over the network. Since
the main entry point to Facebook is via the facebook_session, it
is convenient to stub out calls to the facebook_session. Here’s an
example:
stubbing_example.rb
def test_friends
stubbed_user = stub(:friends => “1,2,3”)
Facebooker::Session.any_instance.stubs(:user).returns(stubbed_user)
facebook_post ‘friends’
assert assigns(:friends)
end
Test accounts
Facebook maintains a special network for developers only, where
you can create fake users for testing. This is great for manual testing
before launching an application. You can also automate this process
by creating acceptance tests via a tool like Selenium. To create a test
acccount, frst create a normal Facebook account. Then go to the test
account page (http://www.facebook.com/developers/become_test_account.php) to
automatically join the developer test network. For more info, see the
wiki (http://wiki.developers.facebook.com/index.php?title=Test_Accounts).
54
Ruby Footprints App
chapter 8
Ruby Footprints is a simple application based on the PHP example-
application footprints. It is an extension of the integrated Facebook
functionality called Poke and is intended to allow users to nudge their
friends by stepping on them. A user will get a notifcation that some-
one has stepped on them and be given the opportunity to retaliate
by stepping back. Many of the code examples come directly from the
running Ruby Footprints application.
Routes
Facebooker tries its best to keep routes looking just like Rails routes.
The main difference is that if your route is for a canvas page, you
should have :conditions => { :canvas => true } appended
to your route. Rails resource routes will also work with Facebooker.
Although all Facebook API calls are POST operations, one of the
fb_params actually passes back the HTTP method used when ini-
tially making the request. Facebooker uses this parameter to simulate
resource routes.
Here is how to specify a route for the Facebook canvas:
map.root, :controller => ‘footprints’, :action => ‘index’, :conditions => { :canvas => true }
For non-canvas routes:
map.root, :controller => ‘footprints’, :action => ‘web’, :conditions => { :canvas => false }
A regular named route:
55
map.remove_user(“remove_user”, :controller => “admin”, :action => “remove_user”)
Resource routes work too:
map.resources :footprints
Models
At the core of the Ruby Footprints application is the FacebookUser
model. The FacebookUser model contains all that we need in order
to be able to communicate with the Facebook API on behalf of a
user. The three pieces of data required are the user’s Facebook ID, a
session key, and the expiration time of the session key. Typically an
application requires access to user data even when the user is not
directly interacting with it, and this is obtained by requiring that the
user add the application. Once this is done Facebook issues an inf-
nite session key for the application to use. The FacebookUser model,
when created, stores all this information in the database and then
uses it to create a Facebooker::Session and to communicate with
the Facebook API. Here is the application before flter used in Ruby
Footprints to create the FacebookUser:
ruby_footprints/app/controllers/application.rb
def setup_db_facebook_user
# Grab the facebook user if we have one
# and store it in the session
unless( @fb_user || facebook_params.empty? )
user_id = facebook_params[“user”]
session_key = facebook_params[“session_key”]
expires = facebook_params[“expires”]
fb_user = FacebookUser.ensure_create_user(user_id)
models
The creation and management of the Face-
bookUser model has a couple of unique things
that you don’t always see in a Rails applica-
tion. The frst is the call in the before_flter
to the method FacebookUser.ensure_cre-
ate_user. Typically what you would see here
is a call to FacebookUser.fnd_or_create_
by_uid(). This turns out to not be suffcient for
any application that carries a signifcant load.
The reason is that the create is not transaction-
ally safe and the database will either end up
will duplicate rows or if there is a unique key on
uid then an database constraint error will be
thrown. The second unique piece of code is the
check for the session_key changing. This can
happen if the user removes the application and
then later adds it again. This check would not
be necessary if the application deletes users
from the database upon remove.
Another thing to note is that Facebook User id’s
are 64 bit integers and the current Rails migra-
tions do not support this as it is not database
agnostic. MySQL and other databases can
support 64 bit integers and there is a plugin for
handling it (http://agilewebdevelopment.com/plugins/
mysql_bigint).
56
if( fb_user.session_key != session_key || fb_user.last_access.nil? || fb_user.last_access <
(Date.today.to_time - 1 ))
fb_user.session_key = session_key
fb_user.session_expires = expires
@previous_access = fb_user.last_access
fb_user.last_access = Date.today
fb_user.save!
end
@fb_user = fb_user
end
session[:current_user] = @fb_user
@fb_user.facebooker_session = (@facebook_session || session[:facebook_session])
return @fb_user
end
def publish_story_to_user
if(@previous_access && (@previous_access < Time.parse(Date.today.to_s)) )
FacebookPublisher.deliver_nudge_story(current_user)
end
end
Now that the model contains a session key, uid, and expiration time,
it has the ability to create a Facebooker::Session to communicate
with the Facebook API. The API is typically called with either a ses-
sion object or a Facebooker::User object. FacebookerUser provides
access to both via these two methods:
ruby_footprints/app/models/facebook_user.rb
def facebooker_session
unless(@facebooker_session)
@facebooker_session = Facebooker::Session.create(ENV[‘FACEBOOK_API_KEY’], ENV[‘FACEBOOK_SECRET_
KEY’])
@facebooker_session.secure_with!(self.session_key,self.uid,0)
@facebooker_session.user.uid = self.uid
end
@facebooker_session
57
end
def facebooker_user
@facebooker_user ||= facebooker_session.user
end
Now that the FacebookUser model can access an API session
it can be set up to delegate method requests to the enclosed
Facebooker::User, which is done via method_missing and allows an
instance to quack like a Facebooker::User.
ruby_footprints/app/models/facebook_user.rb
def method_missing(symbol , *args)
begin
value = super
rescue NoMethodError => err
if(facebooker_user.respond_to?(symbol))
value = facebooker_user.send(symbol,*args)
return value
else
throw err
end
end
end
note There are instances inside the Facebooker code that
explicitly validate that it has been passed an instance of a
Facebooker::User, so even though the model delegates its
methods to an instance of Facebooker::User the method will still
throw an exception.
58
Advanced Topics
chapter 9
FBML and Image Caching
References are a little hidden treasure in the Facebook platform. They
allow you to cache a bunch of FBML on Facebook’s servers that can
later be retrieved using a special FBML tag, <fb:ref>. The advantage
of caching FBML is that your application doesn’t have to dynami-
cally generate it each time for each user. But the real magic lies in
the ability to fre off an API command that will instantly push out the
cached FBML to wherever it is referenced. For example, if you have
an application that applies the same FBML to each user’s profle, you
can call just one API command that instantly updates it on each pro-
fle without you having to manually publish it for each user.
Refs are great for storing large chunks of FBML. You can even use
them in creative ways, such as making your CSS a ref and updat-
ing the ref anytime you change the CSS in order to update the view
across all your users’ profles. A common use is to have an admin
section for your site that uses refs to update code that is common
across all profles, like CSS. It is also perfect if you have an app that
publishes static content, like sports scores.
Handle Refs
There are two ways to cache FBML. The simplest way is to defne a
key value pair, where the key is a unique handle or identifer for the
reference, and the value is the FBML content. You set the cache using:
facebook_session.server_cache.set_ref_handle(‘handle’, ‘FBML content’)
59
Then “FBML content” will be replaced anytime you have:
<fb:ref handle=”handle”/>
URL Refs
Facebook gives us another option for caching: you can store the
FBML at a URL which will be cached by Facebook’s servers. Set and
refresh the URL with:
facebook_session.sever_cache.refresh_ref_url(:url => “http://url_for_cached_fbml”)
This URL will be cached by Facebook until you call the method again.
As with handle refs, you can access the content with:
<fb:ref url=”http://url_for_cached_fbml”/>
Handle refs are preferred over URL refs because they are set in real-
time as opposed to being retrieved from your server when needed.
If your server happens to be down and has a maintenance page up,
then it is possible for your content to actually be the maintenance
page when using URL refs. Furthermore, if you use URL refs exten-
sively, and a torrent of requests come in, it is possible to overload
your servers. Facebook also seems to have a high rate of failure with
retrieving URL refs. Another reason to use handle refs is because
they are left unchanged when a failure occurs. If a failure occurs while
requesting a URL ref, the content will get flled up with garbage.
Image Caching
Images that are shown on non-canvas pages, such as in profles and
60
Mini-Feeds, can also be explicitly cached by Facebook servers.
facebook_session.sever_cache.refresh_img_src(:url => “http://url_for_cached_image”)
They can be accessed with:
<fb:ref url=”http://url_for_cached_image”/>
Images that are served to Facebook canvas pages are automatically
cached by Facebook on the frst request. The above is mainly useful
for the same reason that handle and URL refs are useful; an image
that is identical across many profles can be updated in one go using
this method.
Bebo
Recently we added support into Facebooker that allows your Rails
instance to simultaneously support both Facebook and Bebo (http://
bebo.com). Bebo supports the current API provided by Facebook; how-
ever, there is little indication that Bebo will be embracing the next
version of the Profle and API. That being said, the differences are
not big enough that they can’t be coded around. In order to support
Bebo you will have to go through the same steps to create an appli-
cation on Bebo that you did within the Facebook developer applica-
tion. After doing this you will be given an api_key and a secret_key
that can be put into your facebooker.yml. To setup your yaml fle
you will need to add 5 key value pairs as shown in the example below:
development:
api_key: 921628d9d70f5e0b5887936802abe9e6
secret_key: 77sEcRETsecretSECRET3ce96c
canvas_page_name: ruby_footprints
callback_url: http://rfootprints.shacknet.nu
61
bebo_api_key: abc45673de67f2234682919810adece7
bebo_secret_key: 77sEcRETsecretSECRET3ce96c
bebo_canvas_page_name: bebo_ruby_foot
bebo_callback_url: http://rfootprints.shacknet.nu
bebo_adapter: BeboAdpater
The most important key is bebo_adapter. This key tells Face-
boker to load the Facebooker::BeboAdpater class instead of the
Facebook::FacebookAdapter class. This adapter contains all the
information needed to talk to the Bebo API and to generate Bebo-
specifc canvas page URLS. They’re handled with a before flter on
ApplicationController that will look at the incoming api_key, look
up the correct confguration for that api_key, and load the appropri-
ate Adapter. Occasionally it will be necessary to load a particular
Adapter manually. This can be done by calling Facebooker.load_
adapter(“bebo”) since the default adapter is always the Facebook-
Adapter.
There are some differences in the Bebo container and most of
these are discovered along the way. In order to support conditional
rendering of Bebo-specifc FBML, you can call Facebooker.is_
for?(:bebo).
62
Appendix: Terminology
chapter 10
Term Description
Canvas page The page where your
application runs inside
Facebook.
Callback URL The URL where your appli-
cation is hosted.
News feed Recent friend activity that
shows up on the main
Facebook page
Mini-Feed Recent friend activity that
shows up on user profle
pages
Notifcation Friend and app invites/
communication, tab under
Inbox
Wide profle Box on the right side of the
profle page
Narrow profle Box on the left side of the
profle page
Wall Comments section on the
profle page, most recent
post shown on top
63
Appendix: Models
chapter 11
Affliation
name
nid
status
type
year
Album
aid
cover_pid
created
description
link
location
modifed
name
owner
size
ApplicationProperties
about_url
application_name
callback_url
dashboard_url
default_column
default_fbml
description
desktop
dev_mode
edit_url
email
help_url
installable
ip_list
is_mobile
message_action
message_url
post_install_url
preload_fql
privacy_url
private_install
see_all_url
tos_url
uninstall_url
use_iframe
Cookie
expires
name
path
uid
value
EducationInfo
concentrations
degree
name
year
HighschoolInfo
grad_year
hs1_id
hs1_name
hs2_id
hs2_name
Event
creator
description
eid
end_time
event_subtype
event_type
host
location
name
nid
pic
pic_big
pic_small
start_time
tagline
update_time
venue
Attendance
eid
rsvp_status
uid
64
FriendList
fid
name
Group
creator
description
gid
group_subtype
group_type
name
nid
offce
pic
pic_big
pic_small
recent_news
update_time
venue
website
Membership
gid
position
uid
InfoItem
description
image
label
link
sublabel
InfoSection
feld
items
Location
city
country
state
zip
Notifcations
event_invites
friend_requests
group_invites
messages
pokes
shares
Photo
aid
caption
created
link
owner
pid
src
src_big
src_small
title
Tag
pid
subject
xcoord
ycoord
65
User
about_me
activities
affliations
birthday
books
current_location
education_history
frst_name
has_added_app
hometown_location
hs_info
id
interests
is_app_user
last_name
meeting_for
meeting_sex
movies
music
name
notes_count
pic
pic_big
pic_small
pic_square
political
profle_update_time
User
quotes
relationship_status
religion
session
sex
signifcant_other_id
status
timezone
tv
uid
wall_count
work_history
Status
message
time
WorkInfo
company_name
description
end_date
location
position
start_date
66
The Authors
David Clements
David has been doing Ruby On Rails consulting for over three years
and is currently acting as Director of Web Development for Meeting-
Wave (wwww.meetingwave.com). His current focus is on providing value
through Social Networking integrations on the Facebook, Bebo and
the iPhone Platforms. As regular contributor to the Facebooker library
he also maintains the Facebooker Tutorial (http://apps.facebook.com/
facebooker_tutorial) application on Facebook. He lives in sunny Boulder,
Colorado and occasionally fnds time for Mountain Biking and Snow-
boarding. He can be reached at david.g.clements@gmail.com or on
Facebook (http://www.facebook.com/profile.php?id=830904376).
Shane Vitarana
Shane is a programmer living in Chicago, IL, and is one of the com-
mitters on the Facebooker Rails plugin. He has built a handful of
Facebook applications, with the most popular being Video Jukebox
(http://apps.facebook.com/jookbox). He has worked for some big companies
such as Motorola and Orbitz, but is now an independent developer.
Shane started programming at the tender age of 12 and has worked
on a broad range of platforms and languages. He is currently trying
to apply his Facebook experience to the iPhone application market.
He has a few applications in the iTunes App Store and working on
more. When he is not on a coding binge, he likes to play the drums
and ride a snowboard. His application, Drum Kit, is one of the Top 25
selling iPhone apps.
Check out Shane’s iPhone apps in the App Store (http://phobos.apple.
com/WebObjects/MZStore.woa/wa/viewArtist?id=284976112).
67
Credits
Thanks to Michael Neissner for reviewing the book, and everyone at
PeepCode for amazing layout, design, and editing.
Revisions
January 7, 2009 – Corrected name of facebooker:setup rake task. •

Sign up to vote on this title
UsefulNot useful