Facebooker configs in database

Posted: February 22nd, 2010 | Author: Pierre Olivier Martel | Filed under: Facebook, Rails | 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.


Collaborative Facebook development with Facebooker

Posted: February 16th, 2010 | Author: Pierre Olivier Martel | Filed under: Facebook, Rails | 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.


Rails geopositioning with Google Maps

Posted: October 1st, 2009 | Author: Pierre Olivier Martel | Filed under: Rails | Comments

A common problem when building a Rails web application that deals with addresses is geopositioning. Geopositioning can have different meaning depending on what you’re trying to achieve. In this article and the following, I will describe my solution to the following problems :

  1. The user enters an address and you need to validate it and geoposition it (latitude & longitude) on a map.
  2. You need to display the google map for that given address on a webpage.

Today, I will show you how I did the first step using the YM4R/GM plugin.

1- Setup the plugin and get you Google Maps key

First thing to do is to install the YM4R/GM plugin plugin. There is also a gem but it seems to be a stripped-down version of the plugin. I couldn’t get it working so I would advise to use the plugin :

script/plugin install svn://rubyforge.org/var/svn/ym4r/Plugins/GM/trunk/ym4r_gm

The plugin creates a file in your config folder named gmaps_api_key.xml. You need to enter your Google Maps API keys for the different environments. You can get the keys here.

2- Create the model

Next thing to do is to create your Geolocation activerecord model. You need to at least have those four attributes :

create_table "geolocations", :force => true do |t|
  t.string   "address"
  t.string   "city"
  t.float    "latitude"
  t.float    "longitude"
end

You might also want to add the country and postal code to the mix. But in most case, Google Maps will be able to return you a location with just a street address and a city.

3- Set the geolocation on the before_save

When you create a new gelocation record, you want to geoposition it. Here’s my code in the Geolocation.rb model :

before_save :set_geolocation

def set_geolocation
  if changes['address'] || changes['city'] || !mapped?
    results = Geocoding::get(complete_address)
    if results.status == Geocoding::GEO_SUCCESS
      self.latitude, self.longitude = results[0].latlon
    else  
      self.latitude, self.longitude = nil
    end
  end
end

def complete_address
  [address, city].select(&:present?).join(', ')
end

def mapped?
  latitude && longitude
end

What this does is set the latitude and longitude for the given address on the before_save callback. We first check if the address or the city changed and if so we try to get a geocoding. If the API responds with SUCCESS, we set the latitude and longitude with the first result. If the API failed to return a valid address, we set the latitude and longitude to nil. We can check if the address was mapped using the mapped? method.

4- Wrap it up

Geopositionning the address is only the first part of the problem. Next week I’ll show you how to use the latitude and longitude information we stored to display Google maps in your webpages.

Next week : How to display a google map for a geopositioned address