Pushrod

Old dogs, new tricks

Archive for the ‘facebook’ Category

Facebook templates made easy with Rails 2.0 custom Mime types

with 3 comments

I’ve written elsewhere about how I used my own lightweight library to add Facebook functionality to Autopendium :Stuff About Old Cars, the classic car community website I run.

The library has made it fairly easy to keep up with Facebook’s many changes, and the Facebook app has been a good marketing tool for the site. But adding more functionality to the app has meant duplicating code, as all the actions are handled by a FacebookController.

However, now that I’ve updated to Rails 2.0, adding Facebook functionality is a whole lot easier, and the solution is so simple, I’m sure it’s a common usage pattern.

Let’s take the Autopendium classic car events calendar, which we’ve just introduced:


I don’t really want to do an events action in the FacebookController just to make it available in the Facebook app; I’d rather just use the EventsController#index action and render it with a custom template. (We’re already doing something similar for ics MimeTypes — serving up the events in iCalendar format, so they can be imported directly into your electronic calendar, but that’s for another post).

Custom Mime Types to the rescue

With the new custom Mime types in Rails 2.0, it’s a breeze. Often these are used for customising apps for the iPhone (as shown here), but I reckoned the situation was pretty similar with integrating Facebook interfaces to existing apps.

If the request comes in via the the Facebook canvas we need all the custom Facebook FBML to specify style, etc (and even if you’re using an iframe, you’ll probably want a custom layout).

So this is what I did. First, add a custom facebook mimetype in your environment file:

 Mime::Type.register_alias "text/html", :facebook

Then you need to some way to recognize you’ve received a request from your Facebook app.

You could do a check on the params, as all requests from Facebook have a number of Facebook-specific parameters (fb_sig, etc, which is covered briefly in the second part of my Facebook lightweight library posts). This has the added advantage that you can use the normal URLs in your facebook templates/links. However, if you’re using REST-type routes — as I am — you may end up with difficulties for the moment, as all request from Facebook are POSTs. (According to FB, this may change in the future and already there’s a parameter in the request which says what method the original request was.)

A simpler way is to use the routes (or possibly a subdomain, as shown in the iPhone example). I’ve already got the Autopendium FB app set up so that all request from Facebook have a base URL of autopendium.com/facebook/ (i.e. what Facebook calls the callback URL) . This normally sends everything to the Facebook controller, so /facebook/latest goes to the #latest action in the FacebookController. However, if I add a couple of line to my routes.rb file:

map.connect 'facebook/:controller', :format => 'facebook', :action => 'index'
map.connect 'facebook/:controller/:id', :format => 'facebook', :action => 'show'

… I get facebook/events (which is generated by a link in the Facebook canvas of apps.facebook.com/autopendium/events routing to the index action in the Events controller with our custom :facebook format. Likewise facebook/events/3 will route to the show action in the Events controller with an :id of 3 in the params hash.

Then in my Events controller, I just add an additional line to the respond_to block:

respond_to do |format|
format.html # index.html.erb
...
format.facebook # index.facebook.erb
end

This means the response for the Facebook request will be served using a special facebook template, with no render :template => “special_facebook_template” needed.

Classic Car Events in Facebook

Even better, if it will automatically use a custom facebook application layout if it exists (called application.facebook.erb). So all your standard links, frame, css can be included without a single extra line. Mine looks something like this:

<%= stylesheet_link_tag "facebook_basic" %>
<fb:header decoration="add_border">Autopendium :: Stuff about old cars</fb:header>
<br />
<fb:tabs>
<fb:tab_item href="http://apps.facebook.com/autopendium" title="Intro">Intro</fb:tab_item>
<fb:tab_item href="http://apps.facebook.com/autopendium/show" title="My Autopendium">My Autopendium</fb:tab_item>
<fb:tab_item href="http://apps.facebook.com/autopendium/events" title="Classic Car Events">Classic Car Events</fb:tab_item>
</fb:tabs>
<div class="container">
<%= yield  %>
</div>

Written by ctagg

April 12, 2008 at 12:54 pm

Facebook, hyperactive APIs and lightweight libraries

with one comment

Probably the single biggest annoyances with writing (and running) a Facebook app is the remorseless changing of the API, to the extent that you begin to wonder sometimes whether it’s worth it.

For those who’ve not yet made the plunge, we’re not talking about minor tweaks, or once-in-a blue-moon essential maintainence that’s introduced over several months.

Oh no. With the Facebook API, you get major, app-breaking changes that are introduced with just a few weeks’ notice. The latest one got people so excited, it even made TechMeme’s front page:

TechMeme Facebook API change

Recent highlights include the deprecation of the whole method of sending invitations to other users, which is a central part of most applications, yet was scheduled to happen in “around 2-3 weeks” after the announcement.

So what’s a person to do? Duck out of the whole Facebook thing? Hope that OpenSocial solves all your problems, providing a standardized, flexible, and stable interface to a who bundle of social networks? Don’t hold your breath — it’s only at version 0.5 at the moment – and they are quite open that it’s going to change, and change rapidly.

The other option is to hang on and ride out the bumps, which is what I’m doing with Autopendium, the old-car community website I run, which gets a steady stream of new users thanks to its Facebook app, which keeps your profile and feed up-to-date with your old cars.

The most recent change I had to sort out was the introduction of templatized (ugh!) feed notifications, which will be replacing feed.publishActionOfUser in time.

In many respects, this was an easy change, certainly much easier than changing the whole invite procedure, which required rewriting the controller actions both for showing friends to invite, and sending the invitations (at least it would have been, if I’d carefully read the API).

The Autopendium app updates users feed whenever they add a new vehicle, or add a running report entry to one of their existing vehicles, using my favourite method of observers, specifically using a general FacebookObserver class, and my lightweight facebook library.

class FacebookObserver < ActiveRecord::Observer   
  observe Vehicle, Post
    def after_create(obj)
      update_facebook_info(obj)
   end  

  private   
  def update_facebook_info(obj)     
    user = obj.user
    return true unless @facebook = user.facebook # instantiate facebook session object from user
    update_profile_box_of(user) # update their profile
    publish_action_about(obj) # and their newsfeed too
  end

  ...    

  def  publish_action_about(obj)
     title = "<fb:userlink uid='#{@facebook.user}'/> added a new vehicle on Autopendium"
     body = "#{obj.title}: #{obj.description[0..80]}..."
     @facebook.fb_feed_publish_action_of_user(:title => title, :body => body)
   end
 end

To change this to the new feed.publishTemplatizedAction you only need to change a couple of line, specifically:

  def  publish_action_about(obj)
     title_template = "{actor} added a new vehicle on Autopendium"
     body_general = "#{obj.title}: #{obj.description[0..80]}..."
     @facebook.fb_feed_publish_action_of_user(:title_template => title_template, 
        :body_general => body_general, :actor_id =&gt @facebook.user)
   end

What makes this such a breeze is having all the Facebook updating done in an observer, rather than in the various controllers, and, I think, the fact that the Facebook library is so transparent, meaning it’s easy to change, add or remove methods as Facebook does.

There is a downside, however, and it’s that fairly eloquently explained by Chad Fowler, when discussing his Facebook library, Facebooker. In brief, “If Facebooker didn’t hide the implementation details of the XML API from its end-users, a change in the XML API would require every application which uses Facebooker to change.”

Essentially, the great thing about it is that the app (and the developer) doesn’t need to worry about Facebook changing its API, because that’s the library’s job. Which is great. We like things that make our life easier. Except…

Except that when something’s changing as much and as fast as the Facebook API, I think it falls down. I think there are three main problems with this ‘black box’ approach:

  1. It assumes the black box is updated as frequently as the API. Now in the case of Chad’s library, that seems to be the case (it’s had well over 100 commits and even has support for templatized actions). However, I got myself into trouble with Ruby/Amazon, which is no longer supported and is stuck at version 3 of Amazon’s API (and thus dead from early next year). I moved to the much more straightforward amazon-ecs, which, ironically, I have abstracted somewhat.
  2. It assumes the API changes can be fully handled by the black box without you having to be aware of them — and I just don’t think that’s the case with Facebook’s API. Even with something as well written and maintained as Facebooker, you still have to subscribe to Facebook’s developer news, and change your code to take account of it, particularly with something like notifications.sendRequest, or feed.publishTemplatizedAction because they force you to change your app or force Facebooker to change its API.
  3. It reduces the time you have to make those changes (again this is not so much of a problem with something like Facebooker, although I’m not sure it’s been formerly released yet) while you wait for the library to catch up, and adds opacity to the process.

So, for me (a relative newbie), a lightweight Facebook library seems the way to go, at least until the API settles down a bit, (and I tend to think it’s not dissimilar to some of the moves Rails has made in moving to 2.0).

Written by ctagg

November 21, 2007 at 9:11 pm

When is a record really updated_at in Ruby on Rails (and the under-overlooked Observer class)?

with 4 comments

Here’s one. When is an item ‘updated’? Well, if you’re using Ruby on Rails, and its automatic timestamps (in particular, updated_at) it’s whenever you save that object. Which is great. One less thing to think about.

However, in the real world, it’s a little more complicated. Take someone’s house. Sure, it changes when the owner changes the core attributes — such as add add another floor to it. But haven’t they also updated it if they give it a makeover, perhaps changed the garden, given it a new front door, painted the windows a different colour, stripped out the mouldings and go all minimalistic inside.

House remodelling —<p> photo by joeltellingPhoto by joeltelling

Depending on how you’ve stored the core attributes of the house (and how much you’ve normalised your models — the house has_many :rooms, has_one :garden, etc), you could completely revamp the house, and it still wouldn’t be updated, at least as far as Rails’ timestamps are concerned. In the case of Autopendium, our old-car website, we’ve had a similar situation. A user’s vehicle has_many :posts (vehicles are essentially blogs devoted to that car, with a few bells and whistles, such as todo lists, associated models and resources, etc).

When would I, as a user, want to be told that a vehicle had been updated? Mainly, when there’s something new been written about it — which, in the case of a restoration, or customisation, usually correlates with something being done to the car. So, we want updated_at to be updated not just when the vehicle record is saved, but also when a new post is created.

Fortunately this is a cinch to solve. If you stop thinking of updated_at as some scary Rails-magic, and think of it as another attribute (albeit one that helpfully gets automatically dealt with when the record is saved), you realise you handle it the same way you’d handle other object whose state depended on that of another one.You could do something like this:

class PostsController < ApplicationController
   def create
     @post = Post.find(params[:id)
     if @post.update_attributes(params[:post])
      @post.vehicle.update_attribute(:updated_at, Time.now)
      ....

A better method is to move it out of the controller and into the Post model. A simple after_create callback should do the trick:

class Post < ActiveRecord::Base
   after_create :timestamp_vehicle
   ....
   private
   def timestamp_vehicle
      vehicle.update_attribute(:updated_at, Time.now) #assumes post belongs_to vehicle and so has a vehicle method
   end

Or you could use the often-overlooked Observer. To quote the Rails API, “Observer classes respond to lifecycle callbacks to implement trigger-like behavior outside the original class.”

So, we create a Observer for the Post model:

class PostObserver < ActiveRecord::Observer
  def after_create(post)
    @post.vehicle.update_attribute(:updated_at, Time.now)
  end
end

In fact, we can slim this down even more, given how the vehicle’s updated_at attribute will be magically updated when we save the vehicle:

class PostObserver < ActiveRecord::Observer
  def after_create(post)
    @post.vehicle.save
  end
end

To activate it we just need to add the following to the environment file in the initialization section:

config.active_record.observers = :post_observer. 

Updated vehicle screenshot

Job done. Both the model callback and the Observer are a helluva lot better than the huge number of SQL craziness when you list a load of vehicles and want to indicate whether each one has been updated (and really is no more an offence against normalisation than counter_cache is).

However, Observers really come into their own when you’ve got multiple models triggering the same behaviour. In the example of a house, you probably want the house to be ‘updated’ when when the colour its painted is changed, when the style is changed, and so on. Here you’d probably wrap it up in a single Observer which watches a whole load of models. Something like:

class UpdatedHouseObserver < ActiveRecord::Observer
  observe Exterior, Style, Garden
  def after_save(record)
    record.house.save
  end
end

I’m also using it in conjunction with my lightweight Facebook library to update a user’s Facebook profile when they add a post or a vehicle (using code in the controller or AR callbacks gets really messy for that).

Update 1: I’ve now posted some details of how I use Observers with the Facebook library.

Update 2: There’s another good post on Observers by Pat Maddox, and specifically a plugin he’s done to make testing with Observers a bit easier.

Written by ctagg

November 9, 2007 at 6:01 pm

The how and why of my streamlined Rails Facebook library

with 22 comments

As I wrote in my previous post (Rails, Ruby, Facebook and tests — my own itch scratched), I needed a Facebook library for Autopendium :: Stuff about old cars, the classic car community site we built on Ruby on Rails, but couldn’t get to grips with the existing library as there were no tests and the code seemed, well, a bit un-ruby-ish.
The solution, particularly given that no one else seemed to have a problem it, was for me to come up with something myself.

First job, try to understand the Facebook API, and in particular the Request/Response cycle. What exactly was going on and what is this Facebook object the documentation talks about?

The ‘Facebook Object’

First thing to know is that the Facebook API is a REST interface. That means there’s no state between requests. So each time you talk to Facebook it’s a fresh request, and the only info it has is that which you pass to it. Similarly, Facebook’s response tells you everything you need to know in that one response.

With this in mind and trying a few dummy requests from the command line with CURL things began to come a bit clearer, especially after looking through the Facebook php library supplied with the Facebook dummy app (my knowledge of php is elementary to say the least, but the naming of the ‘behaviours’ and the comments helped). With that in mind I began to write some dummy controller code:

facebook.fb_users_get_info(:uids => facebook.user, :fields => "first_name, last_name")

It’s worth stressing that I didn’t know what that meant, or how it would be implemented, I just thought that I should be able to ask the mystical facebook object for some info on a given user if it was going to be useful.

Next step was to write some unit tests:

def test_should_be_able_to_instantiate_a_facebook_object
assert FacebookUtilities::Facebook.new
end

Well, duh! But what is a Facebook object already! The main existing library calls it a FacebookSession, which confused me, as it made me think of server-side sessions (that’s probably my fault though). The php library, however, just calls it an object, and we know about those, don’t we. This is Ruby after all.

So the Facebook object is just an instance of the Facebook Class, which defines the Facebook objects behaviours and attributes. Great. That meant, all I had to do was to go through the php library identifying the behaviours, write the (failing) tests, then write the code that made the tests pass.

Simple. Here, for example is the test for generating the Facebook signature (this is the a verification code that’s passed from you to the Facebook API and from the Facebook API to you to confirm it’s a genuine request, and it’s generated using a secret key that Facebook gives you when you register your application).


def test_should_return_signature_from_given_params
fb_object = FacebookUtilities::Facebook.new
assert fb_object.respond_to?(:signature_from)
assert_equal Digest::MD5.hexdigest(FacebookUtilities::FACEBOOK_API_SECRET), fb_object.signature_from
assert_equal Digest::MD5.hexdigest("a_param=1234xb_param=5678yc_param=97531t#{FacebookUtilities::FACEBOOK_API_SECRET}"), fb_object.signature_from({:b_param => "5678y", :c_param => "97531t", :a_param => "1234x"})
end

I derived that from the folowing php code and the Facebook authentication page:

public static function generate_sig($params_array, $secret) {
$str = '';

ksort($params_array);
// Note: make sure that the signature parameter is not already included in
// $params_array.
foreach ($params_array as $k=>$v) {
$str .= “$k=$v”;
}
$str .= $secret;

return md5($str);
}
Once the test was written the code was straightforward:


def signature_from(params={})
request_str = params.collect {|p| "#{p[0].to_s}=#{p[1]}"}.sort.join # build key value pairs, sort in alpha order then join them
return Digest::MD5.hexdigest("#{request_str}#{FACEBOOK_API_SECRET}")
end

And I went through the library like that, simply looking at the behaviour, writing failing tests, then writing the code to make them pass.

In the end, I had a fairly elementary but streamlined library to get any Rails up and working with Facebook in no time. It doesn’t have lots of bells and whistles, but is (hopefully) fairly easy to understand just by reading the code and the tests, and is a cinch to extend and adapt to your particular needs. Oh, and it works for me.

Quick usage guide (for those who don’t like reading code or tests)

1. Download the library from here and the tests from here

2. Put the library in you /lib folder in a file marked facebook_utilities.rb and the tests in your /tests/unit folder in a file called facebook_utilities_test.rb

3. Update the FACEBOOK_API_KEY and FACEBOOK_API_SECRET constants for the ones Facebook gave you when you registered your application (see here for a good article which explains how to do that, and much more).

4. Put “include FacebookUtilities::ControllerUtilities” at the top of any controller you want to Facebook-enable, or at the top of the Application controller if you want it for all your controllers.

5. Call the Facebook object from your controllers using the #facebook convenience method, e.g. facebook.user returns the facebook user id of the user who’s logged into your Facebook app.

There are also a couple of utility methods to use with before_filters: #require_added_fb_app, #require_logged_in_to_fb_app, and #require_fb_frame. These restrict access to facebook users who have, respectively: added your Facebook application, logged in to your Facebook application, or are acessing the application with a Facebook frame (either through an iframe or an FBML canvas).

There’s also an #fb_redirect_to method (aping the similar php one) to use for redirecting to other pages while you’re in the Facebook frame. Briefly, this does a FBML redirect if you’re in a FBML canvas, a javascript redirect if you’re going to another Facebook page (you’re probably in an iframe, and doing an ordinary redirect would result in an iframe within and iframe), and a plain old vanilla redirect_to otherwise.

6. Call any of the methods in the API using a ruby-ized version of the method name preceded with ‘fb_’. So, groups.getMembers which requires a of group id is called by facebook.fb_groups_get_members(:gid => “12345”). You don’t need the api_key, session_key, call_id, sig, or v parameters that are standard required parameters. These are supplied by the facebook object automatically (after all it wouldn’t be much of a Facebook object if it didn’t).

Still confused? Have a play with a dummy app in iframe mode with your app in development mode and a Facebook controller (put something like localhost:3000/facebook in the canvas URL) and check out the requests and responses the console spits out. In development mode, the library logs all the calls and responses to and from Facebook.

Not enough? If the demand is there I might do a bit of a tutorial if I can get the Autopendium Facebook app finished in the next day or so (still getting the FBML right, but that’s another story)

Cheers
Chris
p.s. Sorry about the code formatting. Still getting to grips with WordPress

Updated 15 Aug 07: Added info about controller methods

Written by ctagg

August 15, 2007 at 7:15 pm

Posted in facebook, rails, ruby, testing

Rails, Ruby, Facebook and tests — my own itch scratched

with 8 comments

So I wanted to add a Facebook interface to Autopendium :: Stuff about old cars, the classic car community website that I’ve recently launched (that’s written using Ruby on Rails)

First thought, there must be a Ruby library for Facebook of some sort, probably even a Rails plugin — and there is. But almost from the get-go I had a few problems with it.

1) It was a gem. No problem with that as such, although I tend to be a bit more wary about installing them — they tend to make the code a bit more opaque (i.e. it’s not in my Textmate project drawer), they’re harder to tweak (plugins are dead easy in that respect, especially if you’re using piston), and they can add deployment issues when your in production and deployed across several servers (and yes, I know you can freeze the gems using gemsonrails)

2) There were no tests. Not one. And for dealing with something like Facebook, where authentication and user info was involved that seemed not such a good idea.

It also made it more difficult to understand how the code (and the Facebook API) worked (see 3, below). Perhaps I’d been spoilt by Technoweenie’s plugins that are pretty much solely documented by their tests, but this felt a bit unrailsy to me. So I decided to take a look at the code to see what was going on, perhaps even write a few tests, and I found that…

3) I didn’t understand the code. No, seriously. Felt like I was a 10-year-old reading Joyce. There’s a couple of pretty good posts out there walking you through using the library and setting up a Rails app to power a Facebook app, and by playing around a bit I could get some things working.

But it felt like trying to write a Rails app before I’d read David Black’s excellent Ruby for Rails. I could make things work, but didn’t understand why or how they worked, or why they sometimes didn’t, and that didn’t feel good. Plus, looking at the gem’s code made me more confused because it didn’t really feel like the Ruby I’d come to love and (to an extent) know.

So, I decided that as this must be my problem (nobody else seemed to have a big issue with it), so I should solve it myself. So I sent a couple of days reading the Facebook API, the dummy php app and library that Facebook provides, and doing some tests and some code.

The result is a (very) basic Facebook library that Works For Me. No, really, I mean basic. It’s a single file that I’ve put in my Rails lib folder and include in my facebook controller, and provides access to a Facebook session object.

I haven’t even made a plugin of it yet. Didn’t need to (though it shouldn’t take many minutes, and if there’s any interest in it, I will). But I have written a fair number of tests for it (in fact the tests came first, before the code), and I do feel a have a better understanding of Facebook’s Request/Response cycle, and how to tie that in to an app, especially an existing one like Autopendium. And my itch is now pretty much scratched.

Tomorrow I’ll do a brief walk through the hows and whys of the code, but if anyone wants the code in the meantime (and please do let me know via the comments if/when you find bugs, or generally want to sound off about the code), I’ve pasted it here and the test suite here.

Update: The walkthrough of the library is here

Written by ctagg

August 14, 2007 at 4:23 pm

Posted in facebook, rails, ruby, testing