Adding Facebook Connect to your Rails site with multiple environments
2010 May 04
Facebook Connect is an easy, yet powerful way to drive members of your Facebook network to your site or application, and vice versa. Facebook Connect pairs a registered Facebook Application with a website's URL. This poses a problem for engineers who develop in one environment, test in another, perhaps QA in a third, and deploy to a production server each available at a different URL.
The logical approach to using Facebook Connect would be to pair it with the production environment, and this is not wrong, necessarily. The issue is that the way you register applications with Facebook is to pair them with one specific URL, while your website has several. Let's suppose your application lives in the following environments:
- Dev
- http://localhost:3000
- Test
- http://test.myapp.mycompany.com
- QA
- http://qa.myapp.mycompany.com
- Production
- http://example.com
It's plain to see that the same code base is available at four different URLs. What we obviously don't want is 4 versions of the code base. So, what I've done here, is propose a simple way for the Facebook Connect functionality of your site to be aware of what environment it is running in.
Step 1: Create a new Facebook Application for each environment
This is probably the most tedious part. Head on over to http://www.facebook.com/developers and click on Set Up New Application. Give your application a name, and be sure to include the name of the environment in the name for each except production. This will make it easier to organize as you'll see later. You'll need to do this once for each URL (environment) your website is accessible from.
Step 2: Set the Connect Callback URL
Now that you app is created you'll need to tell Facebook how (or rather, where) to connect to it. Click the "Connect" option on the left-side of the screen and then provide the root level URL for this particular environment. It must be exact (including the port number for localhost).
If, in development, you use any port besides 3000 be sure to note it appropriately here. If for any reason your server is running on another port other than the one you've specified, FB Connect will fail.
Step 3: Instantiate Constants in environment.rb files
So, up until now, we've been telling Facebook how to connect to our site. We also need to make our Rails app aware of Facebook. Assuming each of the environments that our Rails app is running in has a unique, corresponding environment.rb file, we can use these file to set some reqired information about connecting to Facebook. Using the same example from above, let's say your config/environments/ directory contains something like this:
$ ls config/environments/
development.rb test.rb qa.rb production.rb
Open up each of the files in you favorite text editor and at the bottom add this line:
# Facebook
FACEBOOK = { :application_id => 'your_app_id76',
:api_key => 'your_api_key_here_3bf53b8bb8d1e3',
:secret => 'your_secret_here_844b6863c74ba4e'}
Be sure to fill in the correct App ID, API key, and Secret for the environment you're setting up. This is why I told you that including the environment name in the App's title was a good idea! These values are always available on your personal Facebook Applications page.
Step 4: Make your pages aware of FB.Connect and FBML
You'll need to add an attribute to the <html> element and a few lines of Javascript to every page that will be using FB Connect. Fortunately, this is very straight forward in Rails. This code belongs in each layout file that will be using FB Connect. In most applications, this is simply the application layout. So open that file for editing.
To make your pages aware of FBML,
add the following attribute to the <html> element:
xmlns:fb="http://www.facebook.com/2008/fbml"
To make your pages aware of the FB.Connect JS Object, add the following lines to the bottom of your layout:
<script
src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"
type="text/javascript"></script>
<script type="text/javascript">
FB_RequireFeatures(["XFBML"], function(){
<%= "FB.init(\"#{FACEBOOK[:api_key]}\");" %>
});
</script>
Step 5: xd_receiver.html file(s)
Part of this step is optional and part of it is required. I'll begin with the required part. You'll need to make a control file available to Facebook Connect. You may have already been asked to do this and verify it. If not, place the xd_receiver.htm file that Facebook provided (you can also find it at the end of this post) in your application's public/ directory. Once you have done this your application is fully capable of using Facebook Connect correctly in each environment it happens to be running in.
The optional portion of this step involves creating an xd_receiver.htm file for each of your application's environments. I recommend doing this in case you need to make domain specific changes to the xd_receiver.htm file. If you only have one, making a change for one environment may break the file for the other environments.
Begin by creating a new directory in your Rails app under public/ called fb_connect. In this directory create a new directory for each environment your application runs in. In each of the environment directories, place a copy of the xd_receiver.htm file. This is where you will make any environment (domain) specific changes if you need to down the road.
Facebook Connect assumes that it will be able to find xd_receiver.htm immediately under your application's connect URL that you specified in Step 2. We'll need to tell Facebook explicitly where to find the correct xd_receiver.htm file. To do this, open up each environment.rb file and add a new value to our constant:
# Facebook
FACEBOOK = { :application_id => 'your_app_id76',
:api_key => 'your_api_key_here_3bf53b8bb8d1e3',
:secret => 'your_secret_here_844b6863c74ba4e',
:xd_path => '/fb_connect/env_name/xd_receiver.htm'}
And then in our layout file where we initialized FB.Connect, we can pass the path to the xd_receiver.htm file to FB.init.
<script type="text/javascript">
FB_RequireFeatures(["XFBML"], function(){
<%= "FB.init(\"#{FACEBOOK[:api_key]}\", \"#{FACEBOOK[:xd_path]}\");" %>
});
</script>
There you have it. No more telling your PM that "It'll work when it gets to production, I promise." You can now test Facebook Connect functionality in each environment your application lives in.
XD Reciever file: Download
If you're using this approach or need a hand setting it up feel free to contact me.