Absolute urls in Rails – polymorphic_url and a Custom Helper
I was trying to figure out how to cleanly generate absolute URLs from resources in my RSS feed and thought I would put this together. There are several options for generating absolute URLs in different situations. This is probably not exhaustive.
1) resource_url(resource)
Use the resource_url method (rather than the resource_path method). This is standard Rails stuff (api reference). Use this first, but for my situation I didn’t want to specify what kind of resource I was using since my feed handles objects from a couple of different models.
2) :path_only => false
Use the :path_only => false option with url_for (and subsequently link_to). You can read about url_for in the api. I was hoping I could do something like the following.
url_for(@feed_item, :path_only => false)This doesn’t work because url_for takes one argument. That argument can be a lot of things (a hash, an array, a resource object) but you have to pick one.
You could use the :path_only => false option like this:
url_for(:controller => 'posts', :action => 'show', :id => 4, :path_only => false)But I haven’t done something like that since the rails 1.x days and I’m not about to go back.
3) Use polymorphic_url
I haven’t seen this much, but it does exactly what I wanted for my RSS feed:
# In my view:
polymorphic_url(feed_item)
#=> http://127.0.0.1:3000/songs/15-covetedPerfect.
4) Custom Helper Method
Next I added an “enclosure” tag when the RSS item is a song. This makes the feed a little podcasty so that someone could subscribe to it with a podcast client and Google Reader will give you a nice little player.

I’m using paperclip to take care of my attachments. Unfortunately the paperclip attachment#url method only spits out a path and not an absolute urls (which are required for valid enclosure tags). With a heavy heart I added a helper method.
module UrlHelper
# ...
def path_to_url(path)
request.protocol + request.host_with_port + path
end
endSo the final view I ended up with was this.
# in /feeds/show.xml.builder
xml.rss(:version => 2.0, "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
xml.channel do
xml.title "Little Red String RSS Feed"
xml.link "http://littleredstring.com/feed"
xml.description "The recent songs and posts from Little Red String."
xml.language "en-us"
xml.ttl 40
for feed_item in @feed_items
xml.item do
xml.title feed_item.title
xml.description feed_item.description_html
xml.pubDate feed_item.published_at.to_s(:rfc822)
xml.guid polymorphic_url(feed_item)
xml.link polymorphic_url(feed_item)
xml.enclosure render_rss_enclosure(feed_item) if has_enclosure_file?(feed_item)
end
end
end
end
# in feed_helper.rb
module FeedHelper
# These methods only handle mp3s. In the future we may want to have enclosures
# with video as well.
def render_rss_enclosure(feed_item)
file = feed_item.mp3
{:url => path_to_url(file.url), :length => file.size, :type => file.content_type}
end
def has_enclosure_file?(feed_item)
feed_item.respond_to?(:mp3?) && feed_item.mp3?
end
end