SlideShare a Scribd company logo
1 of 67
Download to read offline
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
AdvancedTopics 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 find 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 office 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 profile
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 find music videos on
YouTube, and allows you to embed them on your profile.
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
User
fFaceBooK raILs app
fFaceBooK
raILs app
fFaceBooKUser
•
8
All Facebook API responses have extra Facebook-specific 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 profile 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, reflexive and linked to
the user’s profile
fb_pronoun(uid, options)•	 This also allows for the possessive,
reflexive and objective forms of the pronoun
fb_profile_pic(uid, options)•	 You can control the size of the
profile thumbnail and make it a link to the user’s profile
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 flow control, others are for specific 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 first is that the form is
rendered in a table and as such it can be difficult to style it in certain
ways. The second is that the FBML parser seems to strip out under-
scores from the names of the field elements. So text_field(: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 prefix-
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 prefix 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 confirmation dialog
that will eventually fire 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 file 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 file under
RAILS_ROOT/config.
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 file.
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 find 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 Profile
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 configure 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 profile.
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 file. The Ruby Footprints
facebooker.yml file 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 configuration file 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 first 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 suffice, 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 filter 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
notifications and there are currently two types of session keys, infinite
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_filter.
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 infinite 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 profile
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 identifiers 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 specific 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,
affiliation, 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.profile_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 profile 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
profile_photos method. It simply retrieves all the profile photos for
the currently logged in user.
Events
Facebooker provides a convenience method to get the events for a
user. You can filter 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 profile page. The content of this box can be
rendered differently based on whether users are viewing their friends’
profiles or their own. You also have the option of adding a link under
the user’s profile 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 notifications that are meant to serve as
individual communication between the application and the user. Reg-
ular notifications go to the user’s notification 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 notification is email notifications. 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•	
Notifications•	
Status Updates•	
News feed•	
Requests•	
profile page
Narrow box on left side, under picture•	
Link under profile picture (this is not available in the new Facebook•	
layout)
tabs
Boxes tab: Narrow or Wide profile 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 Profile 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 profile 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
Profile, the Profile
Action and the
Profile FBML. The
Profile Action is
simply a link that goes below a user’s profile picture. The Profile 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 Profile Action, if you set it up
correctly, shows up as a link below every profile that your user looks
at (see Profile Wiki link (http://wiki.developers.facebook.com/index.php/Profile)).
  
Both the Profile FBML and the Profile
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 Profile Action for your
application you actually gain something
very powerful. The link will appear under
the profile for every profile your application
users view, not just the profiles of people
who have added the application. You can
set both defaults in the application settings
page. Here is the default Profile 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-
file. 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 Profile 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, Notifications and Emails, set-
ting a user’s Profile, 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.
Define a method with any number of arguments and call it what-•	
ever you would like, as long as it does not conflict with other
instance methods.
In that method call the method•	 send_as with the type of thing you
are publishing. Available choices are :profile, :email, :notifica-
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 Profile
FBML and Profile 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
Profile for any of your users using a single session key.
With Facebook’s New Profile Design, an application’s Profile Box
can live in one of two places, inside the Boxes Tab and on the
Main Profile 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=”profile” />. If you notice in the example above, the pub-
lisher code calls both profile and profile_main. The call to profile
will set the profile FBML for the Boxes Tab while profile_main will set
the FBML for the user’s Main Profile.
note The Profile 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 final 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 Profile design gives applications a new integration
point. Your application can get access to some coveted real estate
on the user’s profile. Instead of there being application profile boxes
on the main user profile, users will have to select applications that
they would like to highlight on their own profiles. To give your users
access to this tab you configure both the Profile Tab URL and Profile
Tab Name in the application settings. The Profile 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 infinite 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 Profile Box•	
Once your application is setup to support the Profile Tab, when a user
loads that particular tab Facebook will call the Profile 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 Profile (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 flare 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 definitely 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 specific 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 finally release its
new Profile 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 profile pages. Users will be
given control over how Mini-Feed stories appear on their profiles 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-
fix 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 flow 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
Notifications 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 Notification 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
notifications 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 notification to a user
on another user’s behalf, the sender will also get a notification
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 notifications
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 notifications, 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 notifications or emails fail, make sure that you are not
sending any markup other than text and links. Facebook will
happily drop your notification on the floor 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 specifically 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 benefits based on the number of friends that get invited.
The Invitation is handled through a few specific 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 first 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 flash 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 Profile, applications have the ability to provide
lists of data that users can embed into the Info Tab on their Profiles.
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 Profile.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 profile 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 profile and one for publishing to your friends’ profiles. When
you have configured the above, your application will show up in the
drop-down list near the Publisher bar on the Profile page, provided
the user has agreed to show it in your application’s Terms of Service:
48
Your application first 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 first
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 first; this is not very efficient from a programming perspec-
tive but makes the example clearer. Now take a look at the template
definition 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 definitions work exactly like the definitions 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 configuration 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, notifications and requests are
sent.
The limit on Notifications 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 Notifications, 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 first. 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, first 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 notification 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 infi-
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 filter 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 first is the call in the before_filter
to the method FacebookUser.ensure_cre-
ate_user. Typically what you would see here
is a call to FacebookUser.find_or_create_
by_uid(). This turns out to not be sufficient for
any application that carries a significant 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 fire 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 profile, you
can call just one API command that instantly updates it on each pro-
file 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’ profiles. A common use is to have an admin
section for your site that uses refs to update code that is common
across all profiles, 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 define a
key value pair, where the key is a unique handle or identifier 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 filled up with garbage.
Image Caching
Images that are shown on non-canvas pages, such as in profiles 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 first request. The above is mainly useful
for the same reason that handle and URL refs are useful; an image
that is identical across many profiles 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 Profile 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 file
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-
specific canvas page URLS. They’re handled with a before filter on
ApplicationController that will look at the incoming api_key, look
up the correct configuration 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-specific 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 profile
pages
Notification Friend and app invites/
communication, tab under
Inbox
Wide profile Box on the right side of the
profile page
Narrow profile Box on the left side of the
profile page
Wall Comments section on the
profile page, most recent
post shown on top
63
Appendix: Models
chapter 11
Affiliation
name
nid
status
type
year
Album
aid
cover_pid
created
description
link
location
modified
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
flid
name
Group
creator
description
gid
group_subtype
group_type
name
nid
office
pic
pic_big
pic_small
recent_news
update_time
venue
website
Membership
gid
position
uid
InfoItem
description
image
label
link
sublabel
InfoSection
field
items
Location
city
country
state
zip
Notifications
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
affiliations
birthday
books
current_location
education_history
first_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
profile_update_time
User
quotes
relationship_status
religion
session
sex
significant_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 finds 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.•

More Related Content

What's hot

Alphageeks meetup - facebook api
Alphageeks meetup - facebook apiAlphageeks meetup - facebook api
Alphageeks meetup - facebook apiAlphageeks
 
Shiny Agency's Facebook Development Guidelines
Shiny Agency's Facebook Development GuidelinesShiny Agency's Facebook Development Guidelines
Shiny Agency's Facebook Development GuidelinesRoy Pereira
 
Facebook and skype merger
Facebook and skype mergerFacebook and skype merger
Facebook and skype mergerEka Darmadi
 
Facebook api
Facebook api Facebook api
Facebook api snipermkd
 
Top 50+ free search engine submission sites list complete connection
Top 50+ free search engine submission sites list   complete connectionTop 50+ free search engine submission sites list   complete connection
Top 50+ free search engine submission sites list complete connectionEricAlllsen
 
Workshop - How I start my company’s Social Media Plan?
Workshop - How I start my company’s Social Media Plan?Workshop - How I start my company’s Social Media Plan?
Workshop - How I start my company’s Social Media Plan?salomon dayan
 
Case of Face Book MIS Presentation
Case of Face Book MIS PresentationCase of Face Book MIS Presentation
Case of Face Book MIS PresentationTomasEMartinez
 
Ext Js In Action January 2010 (Meap Edition)
Ext Js In Action January 2010 (Meap Edition)Ext Js In Action January 2010 (Meap Edition)
Ext Js In Action January 2010 (Meap Edition)Goran Kljajic
 
funP 開發者俱樂部 十月份聚會
funP 開發者俱樂部 十月份聚會funP 開發者俱樂部 十月份聚會
funP 開發者俱樂部 十月份聚會tutchiio
 
SocialOverlay : P2P Infrastructure for social Networks
SocialOverlay : P2P Infrastructure for social NetworksSocialOverlay : P2P Infrastructure for social Networks
SocialOverlay : P2P Infrastructure for social NetworksBipin
 
Interactive with-facebook
Interactive with-facebookInteractive with-facebook
Interactive with-facebookTien Nguyen
 
Php day 2011 - Interactive-with-facebook
Php day 2011 - Interactive-with-facebookPhp day 2011 - Interactive-with-facebook
Php day 2011 - Interactive-with-facebookQuang Anh Le
 

What's hot (17)

Alphageeks meetup - facebook api
Alphageeks meetup - facebook apiAlphageeks meetup - facebook api
Alphageeks meetup - facebook api
 
Shiny Agency's Facebook Development Guidelines
Shiny Agency's Facebook Development GuidelinesShiny Agency's Facebook Development Guidelines
Shiny Agency's Facebook Development Guidelines
 
Create Facebook Pages
Create Facebook PagesCreate Facebook Pages
Create Facebook Pages
 
Facebook API for iOS
Facebook API for iOSFacebook API for iOS
Facebook API for iOS
 
Facebook Fan Page Promotion
Facebook Fan Page PromotionFacebook Fan Page Promotion
Facebook Fan Page Promotion
 
Facebook and skype merger
Facebook and skype mergerFacebook and skype merger
Facebook and skype merger
 
Facebook api
Facebook api Facebook api
Facebook api
 
Social Network for Facebook
Social Network for FacebookSocial Network for Facebook
Social Network for Facebook
 
Lecture7
Lecture7Lecture7
Lecture7
 
Top 50+ free search engine submission sites list complete connection
Top 50+ free search engine submission sites list   complete connectionTop 50+ free search engine submission sites list   complete connection
Top 50+ free search engine submission sites list complete connection
 
Workshop - How I start my company’s Social Media Plan?
Workshop - How I start my company’s Social Media Plan?Workshop - How I start my company’s Social Media Plan?
Workshop - How I start my company’s Social Media Plan?
 
Case of Face Book MIS Presentation
Case of Face Book MIS PresentationCase of Face Book MIS Presentation
Case of Face Book MIS Presentation
 
Ext Js In Action January 2010 (Meap Edition)
Ext Js In Action January 2010 (Meap Edition)Ext Js In Action January 2010 (Meap Edition)
Ext Js In Action January 2010 (Meap Edition)
 
funP 開發者俱樂部 十月份聚會
funP 開發者俱樂部 十月份聚會funP 開發者俱樂部 十月份聚會
funP 開發者俱樂部 十月份聚會
 
SocialOverlay : P2P Infrastructure for social Networks
SocialOverlay : P2P Infrastructure for social NetworksSocialOverlay : P2P Infrastructure for social Networks
SocialOverlay : P2P Infrastructure for social Networks
 
Interactive with-facebook
Interactive with-facebookInteractive with-facebook
Interactive with-facebook
 
Php day 2011 - Interactive-with-facebook
Php day 2011 - Interactive-with-facebookPhp day 2011 - Interactive-with-facebook
Php day 2011 - Interactive-with-facebook
 

Viewers also liked

Que Es la Tutoria Online
Que Es la Tutoria OnlineQue Es la Tutoria Online
Que Es la Tutoria OnlineNorman Badia
 
El algebra
El algebraEl algebra
El algebrajessy17
 
Currìculo de la empresa
Currìculo de la empresaCurrìculo de la empresa
Currìculo de la empresaErick Gabriel
 
Le Mag de vos finances personnelles Juillet 2016
Le Mag de vos finances personnelles Juillet 2016Le Mag de vos finances personnelles Juillet 2016
Le Mag de vos finances personnelles Juillet 2016Valeur et Capital
 
Anida Actualidad diaria - 1 Junio
Anida Actualidad diaria - 1 JunioAnida Actualidad diaria - 1 Junio
Anida Actualidad diaria - 1 JunioAnidaVivienda
 
Marketing_Digital_SEO_Otimizacao_de_Sites_Redes_Sociais_Links_Patrocinados_SE...
Marketing_Digital_SEO_Otimizacao_de_Sites_Redes_Sociais_Links_Patrocinados_SE...Marketing_Digital_SEO_Otimizacao_de_Sites_Redes_Sociais_Links_Patrocinados_SE...
Marketing_Digital_SEO_Otimizacao_de_Sites_Redes_Sociais_Links_Patrocinados_SE...Web Summit
 
Engel & Voelkers Seminar Tampa with Stefan Swanepoel
Engel & Voelkers Seminar Tampa with Stefan SwanepoelEngel & Voelkers Seminar Tampa with Stefan Swanepoel
Engel & Voelkers Seminar Tampa with Stefan Swanepoelguest3dbf1b7
 
Savage sword of conan 3
Savage sword of conan 3Savage sword of conan 3
Savage sword of conan 3Stripovi Klub
 
Newton enhancement pack_with_grafitty)
Newton enhancement pack_with_grafitty)Newton enhancement pack_with_grafitty)
Newton enhancement pack_with_grafitty)Ігор Ко
 
Curso de productividad personal
Curso de productividad personalCurso de productividad personal
Curso de productividad personaljgrigelmo
 
Indian economy towards growth momentum strategic moves needed
Indian economy towards growth momentum strategic moves neededIndian economy towards growth momentum strategic moves needed
Indian economy towards growth momentum strategic moves neededNeha Sharma
 

Viewers also liked (20)

Tc Management Srs
Tc Management SrsTc Management Srs
Tc Management Srs
 
Powerpoint2007preso
Powerpoint2007presoPowerpoint2007preso
Powerpoint2007preso
 
All
AllAll
All
 
Ruby mine referencecard
Ruby mine referencecardRuby mine referencecard
Ruby mine referencecard
 
Tc Management Srs
Tc Management SrsTc Management Srs
Tc Management Srs
 
Que Es la Tutoria Online
Que Es la Tutoria OnlineQue Es la Tutoria Online
Que Es la Tutoria Online
 
El algebra
El algebraEl algebra
El algebra
 
Currìculo de la empresa
Currìculo de la empresaCurrìculo de la empresa
Currìculo de la empresa
 
Le Mag de vos finances personnelles Juillet 2016
Le Mag de vos finances personnelles Juillet 2016Le Mag de vos finances personnelles Juillet 2016
Le Mag de vos finances personnelles Juillet 2016
 
Anida Actualidad diaria - 1 Junio
Anida Actualidad diaria - 1 JunioAnida Actualidad diaria - 1 Junio
Anida Actualidad diaria - 1 Junio
 
Marketing_Digital_SEO_Otimizacao_de_Sites_Redes_Sociais_Links_Patrocinados_SE...
Marketing_Digital_SEO_Otimizacao_de_Sites_Redes_Sociais_Links_Patrocinados_SE...Marketing_Digital_SEO_Otimizacao_de_Sites_Redes_Sociais_Links_Patrocinados_SE...
Marketing_Digital_SEO_Otimizacao_de_Sites_Redes_Sociais_Links_Patrocinados_SE...
 
Acoso red
Acoso redAcoso red
Acoso red
 
Bitacora 1 mariana
Bitacora 1 marianaBitacora 1 mariana
Bitacora 1 mariana
 
Engel & Voelkers Seminar Tampa with Stefan Swanepoel
Engel & Voelkers Seminar Tampa with Stefan SwanepoelEngel & Voelkers Seminar Tampa with Stefan Swanepoel
Engel & Voelkers Seminar Tampa with Stefan Swanepoel
 
Savage sword of conan 3
Savage sword of conan 3Savage sword of conan 3
Savage sword of conan 3
 
Sistemas de informacion
Sistemas de informacionSistemas de informacion
Sistemas de informacion
 
Newton enhancement pack_with_grafitty)
Newton enhancement pack_with_grafitty)Newton enhancement pack_with_grafitty)
Newton enhancement pack_with_grafitty)
 
Diari d'Alella i Masnou Novembre 2015
Diari d'Alella i Masnou Novembre 2015Diari d'Alella i Masnou Novembre 2015
Diari d'Alella i Masnou Novembre 2015
 
Curso de productividad personal
Curso de productividad personalCurso de productividad personal
Curso de productividad personal
 
Indian economy towards growth momentum strategic moves needed
Indian economy towards growth momentum strategic moves neededIndian economy towards growth momentum strategic moves needed
Indian economy towards growth momentum strategic moves needed
 

Similar to Peepcode facebook-2-rails on facebook

Facebook 3rd Party Api
Facebook 3rd Party ApiFacebook 3rd Party Api
Facebook 3rd Party ApiYoss Cohen
 
Connect with Facebook to Rails Application By Nyros Developer
Connect with Facebook to Rails Application By Nyros DeveloperConnect with Facebook to Rails Application By Nyros Developer
Connect with Facebook to Rails Application By Nyros DeveloperNyros Technologies
 
Facebook plateform architecture presentation
Facebook plateform architecture   presentationFacebook plateform architecture   presentation
Facebook plateform architecture presentationInam Soomro
 
Facebook on Rails
Facebook on RailsFacebook on Rails
Facebook on Railsmc77
 
Facebook Connect Integration
Facebook Connect IntegrationFacebook Connect Integration
Facebook Connect Integrationmujahidslideshare
 
Facebook Technology Stack
Facebook Technology StackFacebook Technology Stack
Facebook Technology StackHusain Ali
 
Facebook Apps Vs Google Open Social
Facebook Apps Vs Google Open SocialFacebook Apps Vs Google Open Social
Facebook Apps Vs Google Open SocialRachel Vacek
 
Facebook API
Facebook APIFacebook API
Facebook APIsnipermkd
 
Facebook
FacebookFacebook
Facebooksonycse
 
Facebook Open Graph Tech Requirements
Facebook Open Graph Tech RequirementsFacebook Open Graph Tech Requirements
Facebook Open Graph Tech RequirementsAffinitive
 
Facebook Platform - Tech
Facebook Platform - TechFacebook Platform - Tech
Facebook Platform - TechDavid Zhuang
 
Whats New On The Facebook Platform Feb 2010 Iskandar
Whats New On The Facebook Platform Feb  2010   IskandarWhats New On The Facebook Platform Feb  2010   Iskandar
Whats New On The Facebook Platform Feb 2010 IskandarNudge Social Media
 
Ikandar Najmuddin - "What's new?"
Ikandar Najmuddin - "What's new?"Ikandar Najmuddin - "What's new?"
Ikandar Najmuddin - "What's new?"iPlatform
 

Similar to Peepcode facebook-2-rails on facebook (20)

Facebook 3rd Party Api
Facebook 3rd Party ApiFacebook 3rd Party Api
Facebook 3rd Party Api
 
Creating a Facebook App
Creating a Facebook AppCreating a Facebook App
Creating a Facebook App
 
Connect with Facebook to Rails Application By Nyros Developer
Connect with Facebook to Rails Application By Nyros DeveloperConnect with Facebook to Rails Application By Nyros Developer
Connect with Facebook to Rails Application By Nyros Developer
 
Facebook plateform architecture presentation
Facebook plateform architecture   presentationFacebook plateform architecture   presentation
Facebook plateform architecture presentation
 
Facebook on Rails
Facebook on RailsFacebook on Rails
Facebook on Rails
 
Facebook Connect Integration
Facebook Connect IntegrationFacebook Connect Integration
Facebook Connect Integration
 
Facebook Coin
Facebook CoinFacebook Coin
Facebook Coin
 
Facebook Technology Stack
Facebook Technology StackFacebook Technology Stack
Facebook Technology Stack
 
Facebook Apps Vs Google Open Social
Facebook Apps Vs Google Open SocialFacebook Apps Vs Google Open Social
Facebook Apps Vs Google Open Social
 
Facebook Apps
Facebook AppsFacebook Apps
Facebook Apps
 
Facebook apps
Facebook appsFacebook apps
Facebook apps
 
Facebook API
Facebook APIFacebook API
Facebook API
 
Facebook Connect
Facebook ConnectFacebook Connect
Facebook Connect
 
Facebook thrift
Facebook thriftFacebook thrift
Facebook thrift
 
Facebook
FacebookFacebook
Facebook
 
Facebook Open Graph Tech Requirements
Facebook Open Graph Tech RequirementsFacebook Open Graph Tech Requirements
Facebook Open Graph Tech Requirements
 
Facebook Platform - Tech
Facebook Platform - TechFacebook Platform - Tech
Facebook Platform - Tech
 
Whats New On The Facebook Platform Feb 2010 Iskandar
Whats New On The Facebook Platform Feb  2010   IskandarWhats New On The Facebook Platform Feb  2010   Iskandar
Whats New On The Facebook Platform Feb 2010 Iskandar
 
Ikandar Najmuddin - "What's new?"
Ikandar Najmuddin - "What's new?"Ikandar Najmuddin - "What's new?"
Ikandar Najmuddin - "What's new?"
 
Web2.0-IFF
Web2.0-IFFWeb2.0-IFF
Web2.0-IFF
 

More from sushilprajapati (15)

Inxero Communicationsplan Template
Inxero Communicationsplan TemplateInxero Communicationsplan Template
Inxero Communicationsplan Template
 
Tools Podcast Financing
Tools Podcast FinancingTools Podcast Financing
Tools Podcast Financing
 
Postal
PostalPostal
Postal
 
Tools Podcast Financing
Tools Podcast FinancingTools Podcast Financing
Tools Podcast Financing
 
Postal
PostalPostal
Postal
 
Postal
PostalPostal
Postal
 
Word2007file
Word2007fileWord2007file
Word2007file
 
Uc Boothpanels
Uc BoothpanelsUc Boothpanels
Uc Boothpanels
 
Test
TestTest
Test
 
Powerpoint2007 preso
Powerpoint2007 presoPowerpoint2007 preso
Powerpoint2007 preso
 
Tc Management Srs
Tc Management SrsTc Management Srs
Tc Management Srs
 
Tc Management Srs
Tc Management SrsTc Management Srs
Tc Management Srs
 
Tc Management Srs
Tc Management SrsTc Management Srs
Tc Management Srs
 
Tc Management Srs
Tc Management SrsTc Management Srs
Tc Management Srs
 
Powerpoint2007preso
Powerpoint2007presoPowerpoint2007preso
Powerpoint2007preso
 

Recently uploaded

Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkPixlogix Infotech
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxfnnc6jmgwh
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024TopCSSGallery
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observabilityitnewsafrica
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...itnewsafrica
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integrationmarketing932765
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 

Recently uploaded (20)

Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App Framework
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 

Peepcode facebook-2-rails on facebook

  • 1. by Shane Vitarana and David Clements $9 Hooking into the network Rails on Facebook
  • 2. 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.
  • 3. 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 AdvancedTopics 58 FBML and Image Caching Bebo Appendix:Terminology 62 Appendix: Models 63 The Authors Credits Revisions
  • 4. 4
  • 5. 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 find 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. 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 office 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 profile 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 find music videos on YouTube, and allows you to embed them on your profile.
  • 7. 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 User fFaceBooK raILs app fFaceBooK raILs app fFaceBooKUser •
  • 8. 8 All Facebook API responses have extra Facebook-specific 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. 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 profile 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, reflexive and linked to the user’s profile fb_pronoun(uid, options)• This also allows for the possessive, reflexive and objective forms of the pronoun fb_profile_pic(uid, options)• You can control the size of the profile thumbnail and make it a link to the user’s profile 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 flow control, others are for specific 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. 10 couple of gotchas with this form helper. The first is that the form is rendered in a table and as such it can be difficult to style it in certain ways. The second is that the FBML parser seems to strip out under- scores from the names of the field elements. So text_field(: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 prefix- 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. 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 prefix 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. 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 confirmation dialog that will eventually fire 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. 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 file 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. 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. 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. 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 file under RAILS_ROOT/config. 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 file. 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. 17 Scrolling down, you will find 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 Profile 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 configure various integration points for your application.
  • 18. 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 profile. 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. 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 file. The Ruby Footprints facebooker.yml file 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. 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 configuration file 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. 21 Hello World This simple application will print “Hello” followed by your first 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 suffice, 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. 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. 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 filter 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. 24 user. These actions can include posting to a news feed or sending notifications and there are currently two types of session keys, infinite 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_filter. 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 infinite 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. 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. 26 Getting Social Data chapter 5 User and Friend Data You can access nearly all the data that is public on a user’s profile 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 identifiers 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 specific 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, affiliation, 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. 27 Facebooker includes a few convenience methods for common photo tasks: facebook_session.user.albums• facebook_session.user.profile_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 profile 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 profile_photos method. It simply retrieves all the profile photos for the currently logged in user. Events Facebooker provides a convenience method to get the events for a user. You can filter 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. 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 profile page. The content of this box can be rendered differently based on whether users are viewing their friends’ profiles or their own. You also have the option of adding a link under the user’s profile 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 notifications that are meant to serve as individual communication between the application and the user. Reg- ular notifications go to the user’s notification 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 notification is email notifications. As expected this sends an email to the user on behalf of your application, as long as
  • 29. 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• Notifications• Status Updates• News feed• Requests• profile page Narrow box on left side, under picture• Link under profile picture (this is not available in the new Facebook• layout) tabs Boxes tab: Narrow or Wide profile box• Application tab• Info tab box• Wall (previously called the Mini-Feed in the old layout)• Status update• email Attachments• Share messages•
  • 30. 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 Profile 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 profile 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 Profile, the Profile Action and the Profile FBML. The Profile Action is simply a link that goes below a user’s profile picture. The Profile FBML
  • 31. 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 Profile Action, if you set it up correctly, shows up as a link below every profile that your user looks at (see Profile Wiki link (http://wiki.developers.facebook.com/index.php/Profile)).    Both the Profile FBML and the Profile 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 Profile Action for your application you actually gain something very powerful. The link will appear under the profile for every profile your application users view, not just the profiles of people who have added the application. You can set both defaults in the application settings page. Here is the default Profile 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- file. The simplest way is through methods directly on an instance of a Facebooker::User. Its available methods are: publish_profile.rb
  • 32. 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 Profile 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, Notifications and Emails, set- ting a user’s Profile, 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. Define a method with any number of arguments and call it what-• ever you would like, as long as it does not conflict with other instance methods. In that method call the method• send_as with the type of thing you are publishing. Available choices are :profile, :email, :notifica- 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 Profile FBML and Profile Action using the Publisher API: ruby_footprints/app/models/facebook_publisher.rb def profile_for_user(user_to_update)
  • 33. 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 Profile for any of your users using a single session key. With Facebook’s New Profile Design, an application’s Profile Box can live in one of two places, inside the Boxes Tab and on the Main Profile 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=”profile” />. If you notice in the example above, the pub- lisher code calls both profile and profile_main. The call to profile will set the profile FBML for the Boxes Tab while profile_main will set the FBML for the user’s Main Profile. note The Profile 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 final edits of this book so we decided to leave it in just in case you see references to it elsewhere.
  • 34. 34 New Profile Application Tab The new Facebook Profile design gives applications a new integration point. Your application can get access to some coveted real estate on the user’s profile. Instead of there being application profile boxes on the main user profile, users will have to select applications that they would like to highlight on their own profiles. To give your users access to this tab you configure both the Profile Tab URL and Profile Tab Name in the application settings. The Profile 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 infinite 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 Profile Box• Once your application is setup to support the Profile Tab, when a user loads that particular tab Facebook will call the Profile 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 Profile (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. 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 flare 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. 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 definitely 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. 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 specific 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. 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 finally release its new Profile 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 profile pages. Users will be given control over how Mini-Feed stories appear on their profiles 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. 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- fix 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 flow 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. 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 Notifications 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 Notification 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 notifications 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. 41 note One thing to note is that when you send a notification to a user on another user’s behalf, the sender will also get a notification 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 notifications 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. 42 end Like notifications, 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 notifications or emails fail, make sure that you are not sending any markup other than text and links. Facebook will happily drop your notification on the floor 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 specifically 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 benefits based on the number of friends that get invited. The Invitation is handled through a few specific 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. 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 first 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. 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 flash 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. 45 Info Section In the New Facebook Profile, applications have the ability to provide lists of data that users can embed into the Info Tab on their Profiles. 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. 46 the application must publish some data to Facebook in a list format. You can check out the wiki for all the details at Profile.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. 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 profile 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 profile and one for publishing to your friends’ profiles. When you have configured the above, your application will show up in the drop-down list near the Publisher bar on the Profile page, provided the user has agreed to show it in your application’s Terms of Service:
  • 48. 48 Your application first 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 first 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. 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 first; this is not very efficient from a programming perspec- tive but makes the example clearer. Now take a look at the template definition 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 definitions work exactly like the definitions used for publishing
  • 50. 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. 51 programmatic configuration Facebook continues to add more and more programmatic access to configuration 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, notifications and requests are sent. The limit on Notifications 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 Notifications, 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. 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 first. Rather, a
  • 53. 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, first 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. 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 notification 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. 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 infi- 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 filter 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 first is the call in the before_filter to the method FacebookUser.ensure_cre- ate_user. Typically what you would see here is a call to FacebookUser.find_or_create_ by_uid(). This turns out to not be sufficient for any application that carries a significant 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. 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. 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. 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 fire 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 profile, you can call just one API command that instantly updates it on each pro- file 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’ profiles. A common use is to have an admin section for your site that uses refs to update code that is common across all profiles, 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 define a key value pair, where the key is a unique handle or identifier 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. 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 filled up with garbage. Image Caching Images that are shown on non-canvas pages, such as in profiles and
  • 60. 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 first request. The above is mainly useful for the same reason that handle and URL refs are useful; an image that is identical across many profiles 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 Profile 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 file 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. 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- specific canvas page URLS. They’re handled with a before filter on ApplicationController that will look at the incoming api_key, look up the correct configuration 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-specific FBML, you can call Facebooker.is_ for?(:bebo).
  • 62. 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 profile pages Notification Friend and app invites/ communication, tab under Inbox Wide profile Box on the right side of the profile page Narrow profile Box on the left side of the profile page Wall Comments section on the profile page, most recent post shown on top
  • 66. 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 finds 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. 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.•