Articles tagged 'routing'

Defer To May 3 2008

So one of the really great features within the Merb router is “defer_to”. This enables you to defer certain routing decisions to runtime, allowing you to evaluate and decide what needs to be handled where based on runtime factors. This is used in a couple of places within Feather and its plugins, specifically the main use is the handling of the article permalinks. Each article has a permalink stored against it, and while there is a default pattern for new articles, we allow any url as a permalink for an article to ensure that importing/backwards compatibility is straightforward. As this may not follow any particular pattern, we need to be able to evaluate this at runtime.

Originally, Feather handled this with a custom Rack handler, that ran before the main Merb application handler. It checked the request uri, and if it matched an article permalink, it dispatched the call to the articles controller to show the appropriate article. If it didn’t match, it simply went on and processed using the Merb app handler as normal. This worked fine, but looked like in the long run it might be difficult to maintain – it would certainly be nice to have a way to handle it all from within Merb routing.

Lo and behold, there is! Enter, defer_to. Let’s take a look at the article matching code from Feather first of all to see how it works:


r.match("").defer_to do |request, path_match|
  unless (article = Article.find_by_permalink(request.uri.to_s.chomp("/"))).nil?
    {:controller => "articles", :action => "show", :id => article.id}
  end
end

So what is this doing? Well it’s basically starting by matching all routes. It then calls “defer_to”, specifying a block to be used to evaluate a request at runtime. This block is passed the incoming request, which is all we need for our purpose here (the second argument is a set of parameters containing information about the route matched so far – in our case we are matching everything to try and then match the permalink at runtime, so we don’t use this argument).

We then basically use the incoming request uri to evaluate whether it matches an article permalink, and if it does we return the routing information for that particular article. Otherwise, the block will just return nothing, and so the Merb router will then continue on its way attempting to find a route that matches for the request. This means that the moment a new article is posted, or perhaps old articles are imported with specific permalinks, they are available and will be handled, all using Merb routing, thanks to “defer_to”. It’s a tidy, lightweight, great way of handling a complex routing problem.

Comments

Page 1 of 1 |