So you want to write a Facebook app written in Rails? Well, the good news is that it works. The bad news is that out of the box Facebook didn’t quite design their platform to work with some of the core concepts (namely, REST) of Rails.
You need to use a great plug-in called Facebooker. Here is a quick set-up guide to help you along, with some tips and pitfalls.
1. Install these two gems
2. Install the plugin
3. add this to your environment.rb file
config.gem “htmlentities”
config.gem “facebooker”
4. configure your facebooker.yml. See the Facebook developer site for your site’s API key and secret. You’ll also put in your canvas path here.
In facebooker.yml, your canvas_page_name is the part first part after apps.facebook.com/ where your users will use your app. You do not need a leading or trailing slash. (In Facebook developer, go to Edit Settings > Canvas > “Canvas Page URL”).
Your callback_url is the URL name where you will operate (include http:// ) and under your facebooker.yml settings is called “Canvas Callback URL.” You don’t need a trailing slash here either. Your users won’t see this URL, because only Facebook will talk to this domain. Therefore, you can safely have it be a subdomain.
api_key: XXXXX
secret_key: YYYYYYY
canvas_page_name: mygreatapp
callback_url: http://www.yourdomain.com
pretty_errors: true
set_asset_host_to_callback_url: true
tunnel:
public_host_username: your_username
public_host: the_tunnel_host
public_port: 3000
local_port: 3000
server_alive_interval: 0
5. I found that your app has to be developed live (or at least live on a dev server). The only other way to develop would be to re-route the network where your local is to be the end-point for the the call from Facebook to your app.
I found that doing it this way was a pain, so I devised this lightweight hack to let you push all your changes up to your github account, then add a post-receive hook in your github repo to trigger your development environment to update itself for every commit you make. Tedious, I know, but effective. (Optional)
def github_pull
output = “Pulling from github…”
output << `/opt/local/bin/git pull`
output << `touch tmp/restart.txt`
render :text => “”
end
git hub pull route
map.connect ‘/github_pull’, :controller => “application”, :action => “github_pull”
7. Create a facebook_controller.rb in the app/controllers folder. I highly recommend this for one important reason: Your app might have parts of it that you don’t want bypass the Facebook authentication (for example, you go to create some kind of an AdminController). All other controllers (the ones your users interact with) should be inherited from the FacebookController (instead of the ApplicationController). That way, you’ll get to keep the Facebook logic inside of this FacebookController. If you have a controller you want outside of the Facebook part of your app, you can make it inherit from the ApplicationController as you normally would.
helper :all
layout “application”
before_filter :current_user
protect_from_forgery
ensure_authenticated_to_facebook
ensure_application_is_installed_by_facebook_user
filter_parameter_logging :fb_sig_friends, :password
def current_user
@current_user ||= User.find_or_create_by_facebook_uid(params[:fb_sig_user])
end
end
8. Map your root route in routes.rb (you have to figure that out yourself based on what you want your canvas page to be).
9. Configure your database.yml, .gitignore, etc.
From here, you can start generating your models. You’ll notice that I added to the FacebookController the assumption that you have a User model with a facebook_uid attribute, so go ahead and generate one now if you haven’t already.
Note: You cannot use the normal scaffold generator. That’s because your
respond_to block in your controllers must have a format line for fbml. This suspends the normal rules of REST and allows all actions to be POST actions. If you don’t do this, you get:
406 Not Acceptable
Your controllers should look like this:
format.fbml
end
And your templates should end with “.fbml.erb”. You can just go ahead and rip out those format.html and format.xml calls – unless you have some funky kind of hybrid app that works in & out of Facebook, you don’t need them.
=== TIPS ===
You can access any of the settings in config/facebook.yml but using the FACEBOOKER global hash, as in:
FACEBOOKER[:canvas_page_name]
If you are using Rails with Passenger and you get this error:
Undefined method rewind and rails 2.3.3
– update passenger to the latest version
sudo gem update passenger
sudo passenger-install-apache2-module