One of the things I found difficult to understand when it comes to writing a Facebook application is how to add a “dynamic” panel to a users’ profile page, and how to auto-add entries to their mini-feed. A couple of examples include:

  • Putting “Nathan has added 5 photos to Flickr” or “Nathan is listening to Computer Camp Love by Datarock” on my mini-feed
  • Adding a dynamic panel to my profile which shows the last 10 patches I have submitted to Ruby on Rails

It turns out this is a fairly trivial exercise with Matt Pizzimenti’s RFacebook gem. The following is a quick run-down of what’s required for adding content to the profiles of users who have installed your (Rails based) Facebook application via a push strategy. I’ve done a gem unpack of hpricot-0.5, json-1.1.0 and rfacebook-0.6.2 to RAILS_ROOT/vendor/plugins.

The “Infinite Session”

In order for you to be able to add content independently of a Facebook user being logged in, you need to have a way of authenticating yourself. When a user is browsing your application through the Facebook interface, the RFacebook library gives you access to the fbsession variable which represents the user who is currently logged into Facebook. The problem is, this session will expire. You can find out when a session will expire by checking the value of fbsession.session_expires.

But surely we don’t want to force a user to log in to Facebook every time we want to update their profile with notifications / new content from our third-party application? So how do we get a session that doesn’t expire? The trick is providing a link to the following URL:

http://www.facebook.com/code_gen.php?v=1.0&api_key=YOUR_API_KEY

Once the user clicks the “Generate” button on that page, every time you call auth.getSession, you’ll get an identical session ID which has a fbsession.session_expires value of 0. While the user is interacting with your Facebook application, you should serialise this to some kind of storage such as the ActiveRecord model of your user so you can use it later:

1
2
3
4
5
6
7
8
9
10
11
class FacebookUser < ActiveRecord::Migration
  def self.up
    create_table :facebook_users do |t|
      t.column :user_id, :string, :null => false
      t.column :infinite_session, :null => false
    end
  end
  def self.down
    drop_table :facebook_users
  end
end

And the sample controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
require 'facebook_rails_controller_extensions'
class FacebookController < ApplicationController
  include RFacebook::RailsControllerExtensions
  
  FB_APP_URL = 'http://apps.facebook.com/my-app-name'
  
  before_filter :require_facebook_login
  before_filter :require_configuration, :except => :configure
  
  def facebook_api_key() 'YOUR_API_KEY'; end
  def facebook_api_secret() 'YOUR_API_SECRET'; end
  def finish_facebook_login() redirect_to FB_APP_URL; end
  
  def require_configuration
    @user = FacebookUser.find_by_user_id(fbsession.session_user_id)
    redirect_to :action => :configure unless @user
  end
  
  def configure
    @user = FacebookUser.find_or_initialize_by_user_id(fbsession.session_user_id)
    unless fbsession.session_expires
      @user.infinite_session = fbsession.session_key
      @user.save!
    end
  end
end

This means we can now run a little script (via cron, if you wish):

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env /path/to/application/script/runner

require 'facebook_rails_controller_extensions'

session = RFacebook::FacebookWebSession.new('YOUR_API_KEY', 'YOUR_API_SECRET')
FacebookUser.find(:all).each do |user|
  session.activate_with_previous_session(user.infinite_session, user.user_id)
  session.profile_setFBML(:uid => user.user_id, :markup => 'My really dynamic content')
  session.feed_publishActionOfUser(:title => 'added some really dynamic content')
end

You could run this script every 5 minutes, or perhaps even directly call session.feed_publishActionOfUser and session.profile_setFBML from your application when the user does something (such as creating a resource).

If you’ve got any examples of where you’ve used this technique, or have any suggestions as to how it could be done better, I’d love to see them. Please comment below :).

11 Responses to “Updating Facebook Profiles and Feeds with RFacebook”

  1. evan Says:

    This was unclear to me, too. Thanks for the straightforward explanation.

  2. Scott Persinger Says:

    We’re not requiring users to click that “Generate” link. Instead we’re just storing their session key and re-using it in our background process. Turns out that most of the sessions we get are infinite anyway.

  3. Nathan de Vries Says:

    @Scott: You’ll only get an infinite session if the user clicks on the “keep me logged in” checkbox when adding the application (which I agree, is most of the time).

    It’s handy to prompt users within the canvas to click the ‘Generate’ link if they haven’t done so, or they’ll wonder why things aren’t working properly.

  4. zeslp Says:

    I tested the code with some revisions to mainly test out feed_publishActionOfUser. The code got executed smoothly with no error, however, what I posted does not show up in the minifeed of myself, nor in that of my friend.

    Any suggestions on how I could identify and fix the problem?

    - Zesko

  5. Mark Says:

    The developer wiki now has the ‘proper’ solution, which is to use your own key since you know that you will have checked off “keep me logged in”. Check it out: http://wiki.developers.facebook.com/index.php/Infinite_session_keys

  6. moe Says:

    Great post. I was doing the same thing. Have you started using handles at all? Makes updating profile a lot simpler and cleaner. Either way, solid post.

    moe

  7. Nathan de Vries Says:

    @moe: To be honest, I haven’t had much time to work on anything Facebook recently. I’ve grown tired of going the hard yards to integrate with what’s essentially a closed system sitting behind a public, proprietary API – much akin to Microsoft’s Blackbird or AOL’s RAINMAN.

  8. Luke Noel-Storr Says:

    Just a quick note to say that the infinite session key generation method given in this article is unnecessary for internal Facebook applications.

    With internal apps, if a user has added your app, the seesion key they have will be infinite. If they haven’t added your app, you won’t need to update their profile anyway!

    The method may apply to external apps, but I wouldn’t know about that.

    Oh – and great article by the way, it helped me understand how the whole profile and feed thing worked.

  9. JasonNg Says:

    I cannot make it work, dunt know what happen to the cron that I made. When I tru execute the cron, error occurs: ../config/../vendor/rails/railties/lib/commands/runner.rb:45: undefined local variable or method `status’ for main:Object (NameError) from (eval):6:in `each’ from (eval):6 from /home/admin/myapp/script/runner:4:in `eval’ from /home/admin/myapp/script/../config/../vendor/rails/railties/lib/commands/runner.rb:45 from /home/admin/myapp/script/runner:4:in `require’ from /home/admin/myapp/script/runner:4

    Please help me to figure this out. Thanks a lot

  10. Rob Says:

    Please help…i am running a very similar script that Nathan is running above (from script/runner). When i run this script from the terminal command line, it executes successfully. However, when the script is run from the cron (using the exact same command) I get the following error:

    /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require’: no such file to load—facebook_web_session (MissingSourceFile)

  11. yagnesh Says:

    i m also facing this problem in wondows os and still not resolved. guide me for solution.

Leave a Reply