Posted: March 25th, 2010 | Author: Pierre Olivier Martel | Filed under: Facebook, Javascript, Rails | View Comments
Developing a Facebook application that runs in a profile tab can be a real pain in the neck. As stated on the Facebook developer wiki, one of the many constrains developing a Facebook tab forbids the use of external javascript files. This means you have to inline your javascript in a script tag in order to be processed by the Facebook FBML parser.
This is a real problem if you have javascript files for your Facebook application and wish to keep your code DRY. Here is the solution I came up with using Ruby on Rails and Facebooker :
# ApplicationController.rb
helper_method :request_is_facebook_tab? # Make the facebooker method available in views and helpers
# Application.fbml.erb
<%= render :partial => 'facebook/fb_js' %>
# _fb_js.fbml.erb
<% if request_is_facebook_tab? %>
<%= javascript_tag output_js_files_content("Utility.js", "FBjqRY.min.js", "application-fb.js") %>
<% else %>
<%= javascript_include_tag "Utility.js", "FBjqRY.min.js", "application-fb.js" %>
<% end %>
# facebook_helper.rb
def output_js_files_content(*files)
output = files.collect { |f| IO.read(File.join(RAILS_ROOT, 'public', 'javascripts', f)) }
output.join("\n")
end
This code will detect wether or not the facebook application is running inside a profile tab. If so, instead of generating an external javascript tag, an helper method is called to dump all the content of javascript files inside a script tag.
This solution lets keep your javascript where it belongs (inside .js files) and keep your code DRY when dealing with profile tabs limitation.
Posted: February 22nd, 2010 | Author: Pierre Olivier Martel | Filed under: Facebook, Rails | View Comments
On a a recent project, I wanted to be able to fetch Facebooker configs from the database instead of the static facebooker.yml config file. This allows for greater flexibility, especially when you need to serve multiple Facebook applications from the same codebase.
In my case, I worked on a donation system on Facebook which is kind of like the Causes Facebook app except that each cause gets its own Facebook app. The Facebook apps are created on the fly from the web admin interface by cause administrators and all the apps point to the same server.
The problem is that Facebooker does not allow serving multiple Facebook applications dynamically. I had to monkey patch it in order to make it work. In my config/initializers folder, I created a new file named facebooker.rb with the following code :
require 'facebooker'
module Facebooker
class << self
def fetch_config_for(api_key)
cause = Cause.find_by_api_key(api_key)
if cause
cause.attributes.merge("callback_url" => Settings.facebook.callback_url)
else
false
end
end
end
end
The fetch_config_for method is called on each request to bind the request to a facebook application configuration. The original method looks for the config in facebooker.yml. This methods overrides that to use a database lookup instead. In the Cause model, I have fields named canvas_page_name, api_key and secret_key. The callback_url is the same for all the apps but it will change depending on the environment. I use the settingslogic plugin to handle that.
Don’t forget to leave a dummy facebooker.yml file in the config folder since it’s loaded when the Facebooker plugins initializes.
Posted: February 16th, 2010 | Author: Pierre Olivier Martel | Filed under: Facebook, Rails | View Comments
I’m currently consulting at Webdweller, a social advertisement platform that integrates with many social networks including Facebook. We are three developers on the team and we all need to collaborate building a Facebook application. Here’s a quick overview of how we did our setup.
1- Setup a local_env.rb file
Create a local_env.rb file in which you will put all your environment variables. This works great with Heroku. This technique is better explained in the article Managing Heroku environment variables for local development. The local_env.rb file is not checked in your version control. It remains on your local development machine and it’s loaded by your environment.rb file. I declare my Tunnlr and Facebook configuration keys this way :
# config/local_env.rb
ENV['FACEBOOK_API_KEY'] = '1cv10ddbd7c4374e70996071343c9ed5'
ENV['FACEBOOK_SECRET_KEY'] = '39c4c4c060a5fd8335a21e22bdb2w26c6'
ENV['FACEBOOK_CALLBACK_URL'] = 'http://web1.tunnlr.com:10521'
ENV['FACEBOOK_CANVAS_PAGE_NAME'] = 'my-facebook-app'
ENV['TUNNLR_PUBLIC_HOST_USERNAME'] = 'tunnlr917'
ENV['TUNNLR_PUBLIC_HOST'] = 'ssh1.tunnlr.com'
ENV['TUNNLR_PUBLIC_PORT'] = '10521'
ENV['TUNNLR_LOCAL_PORT'] = '3000'
# config/environment.rb
# Load heroku vars from local file
# credits: http://tammersaleh.com/posts/managing-heroku-environment-variables-for-local-development
local_env = File.join(RAILS_ROOT, 'config', 'local_env.rb')
load(local_env) if File.exists?(local_env)
Replace those values with your Facebook application keys and tunnlr keys. Each developer is going to need it’s own Facebook App and it’s own Tunnlr account.
2- Put the variables in facebooker.yml
Facebooker.yml is where “facebooker”: fetch its configurations. Reading the Facebooker source code, I realized the file is first parsed in ERB, which lets you put variables in your YAML file. We can put the variables we declared in step 1 :
development: &development
api_key: <%= ENV['FACEBOOK_API_KEY'] %>
secret_key: <%= ENV['FACEBOOK_SECRET_KEY'] %>
callback_url: <%= ENV['FACEBOOK_CALLBACK_URL'] %>
canvas_page_name: <%= ENV['FACEBOOK_CANVAS_PAGE_NAME'] %>
pretty_errors: true
tunnel:
public_host_username: <%= ENV['TUNNLR_PUBLIC_HOST_USERNAME'] %>
public_host: <%= ENV['TUNNLR_PUBLIC_HOST'] %>
public_port: <%= ENV['TUNNLR_PUBLIC_PORT'] %>
local_port: <%= ENV['TUNNLR_LOCAL_PORT'] %>
test:
<<: *development
3- That’s it!
Each developer now has its own configuration for Facebook and Tunnlr and the keys are stored in local_env.rb. This file is not checked in git. This way, all the developers can then share the same facebooker.yml file.
See my other article on speeding up Tunnlr for more tips on developping Facebook applications.