Your SlideShare is downloading. ×
0
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Peepcode facebook-2-rails on facebook
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Peepcode facebook-2-rails on facebook

5,982

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
5,982
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
21
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 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
  • 63. 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. 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. 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. 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.•

×