Pushrod

Old dogs, new tricks

Ditch link_to_remote the unobtrusive way

with one comment

So, Rails 2.0 is out, but the somewhat dubious link_to_remote and other javascript helpers are still there, and haven’t been removed into a plugin, as I think was suggested at one point.

I think that’s a bit of a shame, as it encourages some fairly nasty practices, from filling your code with a series of links all with the same javascript code, to linking to a null anchor by default (and so failing to ecourage a non-javascript option), to putting code inline, when it really doesn’t need to be (and you wouldn’t think of doing that with CSS these days, would you?).

Dan Webb has written about this quite a bit and got me turned onto the whole thing at the Euro Railsconf 06 (see his presentation). He is also responsible for the excellent lowpro, a lightweight extension to Prototype that makes unobtrusive javascript a cinch and has just been updated to work with Prototype 1.6.

Time for an example. In Autopendium, the old car community website I run, when you view the page for a particular model, it shows the Youtube videos for that model. Clicking on the description or thumbnail inserts the Youtube embedded viewer above the videos and starts playing it.

Videos on Autopendium

There’s a number of ways to do this — including using pure javascript to write the HTML for the viewer, either from the video’s id or, if you want more details on the video (rating, date uploaded, tags etc) via Youtube’s API (which can return json if requested).

I’ve gone for a server-side solution, which has the added bonus of allowing me to show the video on a separate page, complete with the video’s title in the page’s title, and the video’s tags in the meta tags. Though the googlebot obviously doesn’t play the video, it does see all the other stuff, which all helps a little, and sends a few extra users my way.Functionality on the Rails side is pretty straightforward. There’s a VideosController, and a #show action, which uses the Youtube video id as the :id parameter, and a responds_to block which renders it in its own page if it’s a regular html request, and via an RJS action if it’s a js request.

As far as the links go, I could of course use link_to_remote:
link_to_remote "View video", {:url => {
:controller => "videos", :action => "show", :id => video.id },
:method => :get }

A bit of a mess, and the output is no better:

<a href="/videos/45" onclick="new Ajax.Request('/videos/45',
{ asynchronous:true, evalScripts:true, method:'get'});
return false;">View video</a>

Perhaps we should add a few font tags while we’re at it…

The Unobtrusive alternative is rather nicer (this assumes you’re adding the lowpro library). In the application helper, define a link helper:

def remote_link_to(text, link, options={})
html_class = "remote #{options.delete(:class)}".strip
link_to(text, link, options.merge({:class => html_class}))
end

This is super simple — it simply appends a remote class to your link. So, for the video viewing link we write

remote_link_to "View video", {:controller => "videos", :action => "show", :id => video.id }

which outputs:

<a href="/videos/45" class="remote" >View video</a>

Then in your application.js, add the following:

Event.addBehavior({"a.remote": function(event) {
this.observe('click', function(event) {
new Ajax.Request(this.href, {asynchronous:true, evalScripts:true, method:'get'});
return false;});})

Job done! Now all links with a class of “remote” will make an Ajax request if called by a js-enabled browser, or a regular request if called by a search engine or non-js-enabled browser.The code is neater, shorter, better, and it works so well I’ve extended the pattern for a couple of other helpers

  • external_link_to — which appends a “external” class, which with pretty much a single line of js means that all such links open up in a new window. I’ve also CSS styled this to show an “external link icon”.
  • modal_link_to — open a modal (floating) box with the result of tan Ajax request using the Control.Modal library

Written by ctagg

December 12, 2007 at 5:52 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

Blatant plug for new ‘Modern Toss’ book

with one comment

An old mate of mine, Mick Bunnage, is one half of the team behind Modern Toss. That would probably be enough for me to give their new book, Work, a plug.

Modern Toss work book

However, it’s also bladder-loosening funny, and definitely NSFW (as much due to the seditious message as the language, though that’s pretty fruity, and all the better for that). Go on, treat yourself (buy from Modern Toss shop, or if you’re feeling poor/mean from Amazon).

If you’ve not heard of Modern Toss yet, check it out at ModernToss.com, get the comic, buy the DVD of the brilliant first series, and look out for the second series on Channel 4 in the new year.

Written by ctagg

November 10, 2007 at 5:50 pm

Posted in irrelevant

Tagged with

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