Friday, October 15, 2010

you will_paginate in FBML!

I hate writing facebook applications. I don't know anyone who enjoys it.

Nevertheless, it's a necessity in todays contracting marketplace, and sometimes we just have to live with the fact that we're going to write facebook apps.

One of the big problems is that all these super useful gems and plugins we use to speed up our development when using ruby on rails (including elements of the rails stack itself) don't really work inside the facebook application paradigm (especially if you're using FBML, which I don't want to, but one of the requirements for this app is a profile tab, and right now there are no other options).

Today, I was saddened when my favorite pagination tool, will_paginate, was rendered useless by the fact that when dealing with FBML, any links have to work according to the facebook routing scheme rather than rails's defaults. It makes sense why, but by default will_paginate was generating URLs for my pagination links that pointed to my routes on the server, which are not the same as my routes within the facebook application (maybe I should have done some better configuration up front. Doh!).

Normally I would start googling like crazy for a solution, but I read a very persuasive blog post yesterday by John Nunemaker on just reading the code on gems you want to learn about rather than trying to google up their interface. So (determined to at least try following the advice of an industry icon such as John), I installed gemedit, and opened up the will_paginate source for the 3.0 prerelease, and found that I could actually very easily customize how will_paginate's links get generated.

In will_paginate, you can specify when you call your link-generating-view-helper just what class you want to render the links. The default is WillPaginate::ViewHelpers::LinkRenderer, which does a whole lot of nifty work with boxing up your pagination situation into a nice set of links (and is very well written for readability, in my opinion). In my case, I just wanted to change how the urls were built, so I created a new class, subclassed the LinkRenderer, overrode just one method (the one that builds a link, cleverly named "link"), and reimplemented it to do the routing the way I needed it. Then, in my view, I specified my custom renderer as the class to use for generating links, and presto, my favorite pagination gem is running again even under the arduous unpleasentries of working from within facebook. See the code below:


class FacebookLinkRenderer < 
  WillPaginate::ViewHelpers::LinkRenderer

  def link(text, target, attributes = {})
    if target.is_a? Fixnum
      attributes[:rel] = rel_value(target)
      target = url(target)
    end
    target = target.gsub "/what_is_wrong","/what_is_right"
    attributes[:href] = target
    tag(:a, text, attributes)
  end

end

And in the view:


#...haml haml haml....

=will_paginate(@items,:renderer=>"FacebookLinkRenderer")

#...haml haml haml....

Nice!

No comments: