… or When Your Customer Doesn’t Share Your Framework’s Opinion

Lately, I’ve been writing a lot of syndication APIs. It’s all about formats, and I happen to agree with Rails that ATOM is the primary XML-based syndication container I want to support. Recently, I had a customer who did not share Rails’ enthusiasm for ATOM, and asked for RSS.

Now clearly, I really didn’t relish making one show.rss.builder for every show.atom.builder I had. Since I’d already used Rails’ atom_feed helper everywhere I had a feed, and since the mappings between ATOM and RSS are reasonably close, I set about trying to make an RSS-ified version of atom_feed.

There are a few issues with this approach - chief amongst which, ATOM has concepts which RSS does not. For these, I've adopted a similar approach to .NET's SyndicationItem class: drop into the ATOM namespace when you've reached the limits of RSS's capabilities.

All you need to do is make sure this helper is required somewhere. The easiest no-code solution is to drop it into /app/helpers. Wherever you require an RSS representation, use

    atom_feed :rssify => true

and continue to refer to ATOM tags and concepts as you would normally. Whistle loudly to yourself while doing this. See? You can almost pretend RSS doesn't exist.

This post is a bit of a waymarker for people who are having a very specific problem (I tried adding this as a comment to this post but was knocked back by an over-zealous spam filter). If you’re using Thinking Sphinx 2.0.1 and acts_as_taggable_on 2.0.6, are looking to index your named tag collections, and are finding your phrasing to the index building gods is resulting in errors or broken SQL, read on.

If you’re using something other than the base :tags collection, you’ll need the following form:

  acts_as_taggable_on :keywords
  define_index do
    indexes keyword_taggings.tag.name, :as => :keywords
  end

Note that the indexes builder requires that you prepend your collection name to _taggings and also that you dereference the text for the tag through tag.name

You *used* to be able to use the indexes keywords.name, :as => :keywords
form above, but as of 1st Dec 2010 it’s not working (see https://github.com/freelancing-god/thinking-sphinx/issues/#issue/167)

In Rails 2, I used to use

ActionController::Routing::Routes::routes_for_controller_and_action_and_keys(
    controller, action, nil)

to get a list of routes that matched a hash. With the advent of Rack-based routing in Rails 3, this approach went the way of the dodo.

I spent a bit of time nosing around in the source for the Rails 3-compatible way of doing this. Like a lot of other useful stuff you can find what you’re looking for under Rails.application, in this case Rails.application.routes, which gives us an ActionDispatch::Routing::RouteSet. This isn’t actually an enumerable or a Set as you’d expect. It has an Array property routes, however. Now if I want a list of routes that use a controller and an action, I can write

    def routes_for_controller_and_action(controller, action)
        routes = Rails.application.routes.routes.select {|r| r.defaults[:controller] == controller && r.defaults[:action] == action}
    end

This is really useful in a usage logging scenario, as we can put a report in front of admins to say which areas of the site are being used most and use a familiar-looking URL rather than the MVC implementation-specific “controller” and “action” nomenclature.

© 2014 ZephyrBlog Suffusion theme by Sayontan Sinha