A service for building, sharing and publishing collections of videos • • • • • • • • Founded: Apr 2006 Launched: Dec 2006 Mark Hall, Scott Persinger, Spencer Miles Self-funded (raising a venture round) Technology: RoR, Apache, PostgreSQL, Softlayer http://geekblog.vodpod.com http://apps.facebook.com/vodpod-videos We're Hiring


Facebook on Rails

Port your app to facebook, using their new F8 Platform 20,000,000+ facebook users Great way to increase exposure to your web site iLike has signed up 3,000,000 users in a few weeks http://apps.facebook.com/vodpod-videos


Backend logic

session management

should be easier with RFacebook 0.6 (we use 0.5.1)

– –

app installation/removal linking facebook accounts to vod:pod user accounts Canvas Page (iframe or fbml) Facebook profile box post activity to a users news feed

Display logic
– –

News Feed

Facebook on Rails

App display consist of two main parts

Canvas Page

Can either be an iframe or fbml (facebook markup language) must be FBML, no javascript support, limited mockajax

Profile box

Profile Box (fbml)

Canvas Page (iframe or fbml)

Facebook Canvas pages are presented within the Facebook frame and can either be FBML or an external html site presented within an iframe.

FBML vs. Iframe

Need to decide whether your canvas page will be FBML or Iframe based FBML

Allows for basic HTML, and unique facebook extension tags

fb:friend-selector, fb:if-is-friends-with-viewer, fb:tabs, fb:wallpost, etc...

Makes it easier to provide a consistent facebook look and feel No javascript support “Mock” Ajax support

– –

FBML vs. Iframe


Requests to the canvas page are redirected to your app server, and displayed in an iframe Pros
● ●

Full html, css, javascript support Easy to port existing rails views You need to write CSS to mimic facebook UI Handy FBML extensions like 'fb:friend-selector' need to be written by hand

● ●

Setting up your App


apply for new key Path on facebook where your app will live http://apps.facebook.com/vodpod-videos/ Path to the facebook app on your servers http://facebook.vodpod.com/facebook/ Requests to the canvas URL will be redirected to the callback URL apps.facebook.com/vodpod-videos/user/spencer -> facebook.vodpod.com/facebook/user/spencer

Canvas Page URL
– –

Callback URL
– – –


Vod:Pod uses rfacebook 0.5.1
– –

Minimal support for Facebook Platform vod:pod uses 0.5.1, rolled our own methods for session management Contains support for the facebook platform Nice controller extensions for managing facebook sessions, logins and app installation
● ● ●

Rfacebook 0.6.1
– –

before_filter :require_facebook_login before_filter :require_facebook_install fbsession

App Installation

User finds your app in directory, or on a friends profile, and clicks “Add”

User is prompted to give your app access to their profile. Upon acceptance, your API key has access to read/write this user profile User is then redirected to an “install” callback URL of your choice

At this we create a vod:pod User, linked to the facebook account We have a 'facebook_uid' column on our users

Session Logic/Workflow

User loads your canvas page for the first time

Facebook GETs your canvas callback url, and passes in an 'auth_token' parameter Vod:Pod App calls facebook API (facebook.auth.getSession) with auth token. Facebook returns session object.

def init_session session[:facebook_session] ||= RFacebook::FacebookWebSession.new(API_KEY, API_SECRET) if params[:auth_token] begin session[:facebook_session].activate_with_token(params[:auth_token]) rescue RFacebook::FacebookSession::RemoteException => e redirect_to session[:facebook_session].get_login_url return false end end end

Session Logic/Workflow, Part 2

User loads your canvas page, is already authenticated and has session
– –

Vod:Pod looks up user with the FB uid. If user exists, sets as the current_user.

before_filter :fb_check_user def fb_check_user # Is the facebook session authenticated? if @fb_session.session_uid # lookup vodpod user user = User.find_by_facebook_uid(@fb_session.session_uid) if user self.current_user = user return end end self.current_user = nil session[:user] = nil end


Lots of methods for querying Facebook users.getInfo, friends.get, feed.publishActionOfUser, profile.setFBML, etc... RFacebook:

Uses hpricot for parsing xml responses

user = fbsession.users_getInfo({:uids => [uid1, uid2, uid3], :fields => ['uid', 'name', 'pic_square']}) (response/'user').each do |user| uid = user.at('uid').inner_html name = user.at('name').inner_html pic_url = user.at('pic_square').inner_html puts “UID: #{uid} end Name: #{name} Pic: #{pic_url}”


Facebook Query Language.

SQL like language for accessing FB data
SELECT uid, name, pic_square FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=211031 OR uid1=1309583)

def get_uninvited_friends(uid) response = fbsession.fql_query( {:query => "SELECT uid, name, pic_square FROM user WHERE \ uid IN (SELECT uid2 FROM friend WHERE uid1=#{uid}) AND NOT is_app_user"}) return (response/'user').sort_by{|u| u.at('name').inner_html} end


See: http://www.livelearncode.com/archives/14

class FacebookController < ApplicationController before_filter :require_facebook_login, :only => [:index] # This will be your canvas page. def index attrs = get_user_attributes(fbsession.session_user_id, [”first_name”, “last_name”]) @firstName = attrs[:first_name] @lastName = attrs[:last_name] end private def get_user_attributes(uid, attributes) response = fbsession.users_getInfo( {:uids => [uid], :fields => attributes}) attrs = {} attributes.each {|key| attrs[key.to_sym] = response.search(key.to_s)[0].inner_html} attrs end end

Creating the Profile FBML Block

Creating the Profile FBML Block
● ●

Call profile.setFBML, with the user_id to update, and the FBML. You need to do this whenever you want to update the profile

fbsession.profile_setFBML({:uid => fbsession.session_uid, :markup => render_to_string(:partial => 'profile_fbml', :locals => {:user => current_user}) })

<fb:title>Vod:Pod Videos</fb:title> <fb:subtitle> <fb:name uid="profileowner" firstnameonly="true" useyou="false"/> has collected <%= pluralize(user.facebook_pod.videos_count, 'video') %>. </fb:subtitle> <% videos = user.facebook_pod.recent_videos(6) %> <div style="margin-left:30px;"> <% videos.each do |video| %> <%= link_to image_tag(video.thumbnail_url), video_url(video) %> <% end %> </div>

Invite Friends to use App
def invite if request.post? begin response = fbsession.notifications_sendRequest( {:to_ids => params[:facebook_uids], :type => 'Vod:Pod', :content => “FBML for the request message”, :image => 'http://www.vodpod.com/images/vodpod_square.gif', :invite => false}) rescue Exception => e return render :text => “error”, :content_type => 'text/plain' end confirm_url = CGI.unescapeHTML ((response/'notifications_sendrequest_response').inner_html) redirect_to "#{confirm_url}&canvas" else render :action => 'invite' end end

Essential for Iframe apps

Post to User's News Feed
def post_feed_item(title) begin fbsession.feed_publishActionOfUser({:uid => fbsession.session_uid, :title => title}) rescue Exception => e log "FACEBOOK: Couldn't post comment to news feed: #{e}" end end post_feed_item "added video #{profile_video_link(groupvideo)}"


Asynchronously posting to user's news feed or profile

Facebook allows for “infinite sessions”, but a user has to explicity sign up for the infinite session, which can't be counted on

Facebook not adding new apps to the directory



API docs, FBML docs, API test console (crappy and limited), FBML test console, Wiki Completely different than developers.facebook.com – GREAT! Discussion forum Create/administer your applications here Rfacebook documentation This presentation

– – –