Developing Facebook applications for Ruby on Rails

Published 20 July 2010

This post is written for Ruby on Rails developers trying to integrate with Facebook, but most of the content is not language specific and may help developers in other languages too.\r\n\r\nh2. Overview – complaints\r\n\r\nWhen you begin developing Facebook applications you will quickly discover it’s a painful process.\r\nDocumentation is generally out of date since the API changes so frequently, so you have no assurance of what you’re reading is still relevent.\r\n\r\nThe \Facebook developers wiki\ has a deprecation notice on the main page, but much of the content still appears to be relevent and useful.\r\n\r\nThe \official developers site\ can be a little difficult to get started with, given the confusing terminology used.\r\n\r\nIf you’re just starting developing for Facebook, expect to be deeply frustrated by the end of the process. Also it’s quite difficult to diagnose problems as they occur (which is often), so expect a lot of deeply disatisfying trial-and-error loops.\r\n\r\nh2. Facebook Connect vs. Social Plugins\r\n\r\nWhen integrating with Facebook you can either put components or widgets on your own site (e.g. the Like button) called Social Plugins, or have a Facebook application, which is fronted (proxied) by Facebook but ultimately served by your server called Facebook Connect.\r\n\r\nThe latter case is what we we’re developing and requires people accessing your site to install your application first. This then appears in their list of applications on their profile page.\r\n\r\nh2. FBML vs. iframes\r\n\r\nYou have two choices when developing a Facebook site, one is to develop in FBML, which is HTML with a few Facebook extensions; and the second is to develop an iframe which is served directly from your server (not intercepted by Facebook) and appears embedded inside the Facebook page.\r\n\r\nDeveloping in FBML means Facebook hits your server with a request for a particular page, interprets all the FBML tags (e.g. ) and substitues them with proper HTML and Javascript, and serves them up to the client.\r\n\r\nDeveloping an iframe application means you’re serving content directly to the client with no Facebook intervention. There is one important caveat to this which is using XFBML. This is a series of tags just like FBML, but instead of Facebook’s servers intercepting and replacing them with HTML before serving them to the client, a client-side Javascript library does this after they’ve been received on the browser.\r\n\r\nSo the process of an iframe with XFBML is this:\r\n\r\n# The client browser accesses your application through a URL like http://app.facebook.com/your-app which includes an iframe in the middle.\r\n# The browser requests this iframe which is linked to your site through whatever URL you’ve configured.\r\n# Your server serves the HTML and XFBML document directly to the client, including a declaration for a Facebook javascript.\r\n# The Facebook javascript then executes onces the page has loaded, reading all the tags and turning them into HTML, including hitting the Facebook server to pull down content.\r\n\r\nThe advantage of this \is discussed here.\ The main deciding factor for us was speed: the little Facebook chat which appears on the bottom right of every Facebook page is large and slow to render. You can avoid the overhead of loading that with every click by running your site through an iframe, since the outer window is not reloaded each time.\r\n\r\nThe downside is the delay on the browser when the page loads. If you have Facebook XFBML tags on the page these will appear only after the Javascript has executed, called the Facebook server to receive the data and rendered them on the page.\r\nSo your users will see a delay before the comments box or like button appear, with the animated \“loading\” icon.\r\n\r\nA consideration for Ruby on Rails developers opting for the FBML method (instead of iframe) is Facebook makes all requests to your server a POST.\r\nThis obviously breaks all your RESTful routes and means you’ll probably have to manually write all your routes for every action in your routes.rb file.\r\n\r\nRegardless of whether you choose FBML or iframe, the Facebook API is available to you client or server side. On the server side we used \the Facebooker gem\ which provides a convenient wrapper around the API, such as ensure_authenticated_to_facebook.\r\n\r\nWe tried to keep hits to facebook to a minimum since they add about an extra 400ms to the response time. You can also achieve this by querying the Facebook API client side.\r\n\r\nAn inconvenience with developing Facebook applications from behind a firewall in your office is you cannot test without deploying. And due to the numerous quirks there’s a lot of hit and miss style development: try something see if it works, nope, repeat until it works.\r\nHaving to do a deployment every 30 seconds makes this problem even more tedious until you give up and start developing on the server (yikes!).\r\n\r\nh2. Getting Started\r\n\r\nTo get started there are a few basic steps:\r\n\r\n* Register your application on Facebook. You will need to add the Facebook Developer application for this. Note also to modify the settings of applications you create, you need to go into the Developer application and look for My Applications.\r\n* Once you’ve created your application you get an API key and secret. You use these whenever you query the Facebook API.\r\n* Create facebooker.yml in your config file. It should look something like this:\r\n@@@\r\ndevelopment:\r\n api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n secret_key: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\r\n canvas_page_name: yoursite\r\n callback_url: http://yourapp.yoursite.com\r\n pretty_errors: true\r\n set_asset_host_to_callback_url: true\r\n \r\ntest:\r\n api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n secret_key: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\r\n canvas_page_name: yoursite\r\n callback_url: http://yourapp.yoursite.com\r\n pretty_errors: true\r\n set_asset_host_to_callback_url: true\r\n@@@\r\n\r\n* When developing your Rails views, inside your layout add the xml namespace to your HTML tag (in HAML):\r\n@@@ ruby\r\n%html{html_attrs(‘en’), \“xmlns:fb\” => \“http://www.facebook.com/2008/fbml\”}\r\n@@@\r\n\r\nif you haven’t yet discovered the joys of HAML use plain old HTML:\r\n\r\n@@@ html\r\n\r\n@@@\r\n\r\n* Also in your layout you need this empty div to appease the angry IE6 gods (directly below the body tag) – in HAML:\r\n\r\n@@@ html\r\n <div id=\“FB_HiddenIFrameContainer\” style=\“display:none; position:absolute; left:-100px; top:-100px; width:0px; height: 0px;\”>

\r\n@@@\r\n\r\n* and directly below the empty div, add the Javascript which does all the XFBML processing:\r\n\r\n@@@ ruby\r\n= javascript_include_tag \“http://static.ak.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php\”\r\n@@@\r\n\r\nnote the exact URL here, previously I had a slightly different URL I’d seen mentioned in some documentation and it was causing random wierdness. This seems to work a lot more reliably.\r\n* You need a file called xd_receiver.htm in your public folder, which contains just this:\r\n\r\n@@@ html\r\n<!DOCTYPE html PUBLIC \“-//W3C//DTD XHTML 1.0 Strict//EN\” \“http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\”>\r\nCross-Domain Receiver Page<script src=\“http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js?2\” type=\“text/javascript\”>\r\n@@@\r\n\r\nthis allows cross-domain communication between your iframe app and the outer Facebook page.\r\n\r\nh2. Begin Development\r\n\r\nNow you should be ready to start developing your application. Most of your development is standard Rails stuff: models, controllers and views.\r\nThe touch points with Facebook is mostly around authentication (inside your application_controller.rb) and adding Facebook widgets to your pages.\r\n\r\nLets say you have a page which you want people to leave comments. To do this simply drop the fb_comments tag on your page (see the facebooker docs for specifics):\r\n\r\n@@@\r\nfb_comments \“arbitrary-unique-id-123\”, true, false, 20, :callbackurl => \“http://app.facebook.com/your-app/your-url\”, :width => 613\r\n@@@\r\n\r\nThe main page’s URL always starts with http://app.facebook.com/your-app and anything after that is appended to the iframe’s URL.\r\nSo http://app.facebook.com/your-app/photo/1 will result in a request to your server to /photo/1\r\n\r\nh3. Checking the current user likes our page\r\n\r\nPart of our application included ensuring the current user is a fan of a particular page. Facebook changed their terminology from \“being a fan\” to \“liking\”. Some out of date documentation or API calls may use the old \“fan\” terminology, but as far as I can tell these are the same thing.\r\n\r\nSo inside our application controller we first check the user is logged into Facebook, and have installed our application.\r\nThen we query to ensure they like our group (which we have the Facebook ID for):\r\n\r\n@@@ ruby\r\n def likes_group?\r\n return true if RAILS_ENV == \“development\”\r\n return current_session.is_fan(1234567890, current_session.user.uid)\r\n end\r\n \r\n def current_session\r\n if facebook_session && !facebook_session.expired?\r\n return facebook_session\r\n end\r\n ensure_authenticated_to_facebook # redirects to the facebook login URL\r\n end\r\n@\r\n\r\nnote the cheat there if we're in development mode we don't try and hit the Facebook API.\r\n\r\nh3. Internet Explorer 6 and 7 bug\r\n\r\nAnother gotcha we discovered in Internet Explorer 6 & 7's handling of cookies means you have to add this to your ApplicationController too:\r\n\r\n@ ruby\r\nclass ApplicationController < ActionController::Base\r\n ...\r\n \r\n before_filter :set_p3p\r\n\r\n def set_p3p\r\n response.headers[\"P3P\"]='CP=\"CAO PSA OUR\"'\r\n end\r\n@\r\n\r\nFor non-rails developers, this is simply setting the \"P3P\" header value on every response.\r\n\r\nh3. Setting the full site host path\r\n\r\nIf you're using the FBML method (not iframe) and you have images or other resoures you want to link to in your site, you will want to specify the full host when creating the links so they are requested directly from your server. If they're relative URLs they'll be requested from http://app.facebook.com/your-app/images/blah.jpg\r\n\r\nIn your Rails ApplicationController there's a method you can override called default_url_options:\r\n\r\n@ ruby\r\n def default_url_options(options)\r\n {:host => \"myapp.mysite.com\"}\r\n end\r\n@@\r\n\r\nh3. Ensuring the user comes through Facebook\r\n\r\nBecause you’re displaying a web page through an iframe embedded inside another web page, you may want to ensure people don’t bypass the outer page and go directly to your site (which they can do in Firefox by right-clicking in the iframe and clicking This Frame → Show Only This Frame).\r\nUnforetunately there’s no easy or elegent way to achieve this. The best you can do is ensure the parameters which Facebook appends to the iframe URL are present.\r\nFacebook appends fb_sig_in_iframe=1 along with several other parameters which you can check the presence of. If you’re really enthusiastic there’s a complicated hashing process you can perform \described here.\. Conclusion\r\n\r\nThis covers most of the stumbling blocks when encountered developing our apps. Hopefully this means you’ll have to spend a little less time discovering this yourself.\r\n\r\nI may write some follow ups with instructions for adding particular functionality in later posts if there’s interest. Please leave a comment.\r\n\r\nIf you get really stuck Arctic Kiwi can develop your Facebook application so you don’t have to. \Please get in touch\