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.
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 :
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 :
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.
In your Geolocation model, start by adding this snippet of code which will initialize your map.
def map
@map ||= prepare_map
end
def mapped?
latitude && longitude
end
def coordinates
[latitude, longitude]
end
private
def prepare_map
return unless mapped?
returning GMap.new("gmap") do |map|
map.control_init(:large_map => true, :map_type => true)
map.center_zoom_init(coordinates, 15) # Set the center and zoo level
map.overlay_init(GMarker.new(coordinates))
end
end
The important method here is prepare_map. What it does is create a new map centered at the given coordinates. The overlay_init method sets a marker at the coordinates position. This is a basic vanilla map initialization. You might want to read the YM4R api for more options like adding an info window or multiple markers.
2. Call it from your controller
In our controller, we will set the @map variable to make it accessible in our view :
@map = customer.geolocation.map
3. Display the map in your view
You will need this snippet of code in the header section of your document to do the proper javascript imports and initializations :
= GMap.header
= @map.to_html
And in the body of your view, where you want to display the map, simply add :
@map.div(:width => 600, :height => 400)
This last line will generate a div with the id “gmap” (or whatever name you set in the GMap.new function). I find it’s cleaner to just set the width an height through CSS.
4. Adding complexity
This technique will only work if you display only one map on the page. The map needs to be visible on page load to be properly displayed. But what if there is multiple maps you want to display on the same page? And what if you want to show them in overlay popups? You probably don’t want to initialize them all on page load since it will freeze the client browser. This will require some javscript hacking. I will show you how to do that next week!