Easy RSS in Rails 2
Of all the methods online for doing RSS in Rails, I’ve found this one to be the most: DRY, flexible, RESTful and extendable. This plugin-free approach is congruent with Rails 2 technique, follows the RSS 2.0 spec and passes W3C validation.
If you’re wanting more than RSS, Rails comes with a helper for creating Atom feeds, called AtomFeedHelper. Each to their own protocol, I prefer RSS because it’s lean.
How to make RSS feeds
Firtly, create a layout for our RSS feeds. We might make more down the track so we save repeating ourselves with this. In my ApplicationController I use layout :application but everyone has different names for their default layouts. I’ll assume you’ve named yours in this style. This layout will be for the RSS mime-type, and will use builder for the template creation so it’ll be called application.rss.builder.
# app/views/layouts/application.rss.builder xml.instruct! :xml, :version => '1.0' xml.rss :version => '2.0', 'xmlns:atom' => 'http://www.w3.org/2005/Atom' do xml << yield end
Next, change the controller. We’re RSS feeds for posts here so we’ll alter the PostsController. In the controller add RSS to the respond_to block:
# app/controllers/posts_controller.rb
def index
@posts = Post.find(:all, :limit => 20, :order => 'created_at DESC')
respond_to do |format|
format.html
format.rss # Add this line so we can respond in RSS format.
end
end
Next comes the template, we name this index.rss.builder for the same reasons we named the layout.
# app/views/posts/index.rss.builder
xml.channel do
# Required to pass W3C validation.
xml.atom :link, nil, {
:href => posts_url(:format => 'rss'),
:rel => 'self', :type => 'application/rss+xml'
}
# Feed basics.
xml.title page_title
xml.description page_title
xml.link posts_url(:format => 'rss')
# Posts.
@posts.each do |post|
xml.item do
xml.title post.title
xml.link post_url(post)
xml.pubDate post.created_at.to_s(:rfc822)
xml.guid post_url(post)
end
end
end
That’s it! You can find the feeds at http://localhost:3000/posts.rss.
How it works
The code is kept simple because we’re making use of Rails conventions to save us from declaring the obvious. Which layout, template and method to use are all handled by Rails routing and response code. Assuming the posts are resources we can reuse the current route for the feed like so:
# Get the URL of the posts in RSS format. posts_path(:format => 'rss') # gives /posts.rss
Extras
Now you’ve got your basic RSS feed in place, it’s time for some extras. There is a lot you can do with RSS but here are my favorites.
Browser support
You can specify the feed for a page in the head of your HTML layout using:
<%= auto_discovery_link_tag(:rss, posts_url(:format => 'rss')) %>
Modern browsers will recognize this and let the user know RSS is supported at this location.
Feed icons
Pimp your new feeds using art from feedicons.com.
RSS sugar
We can add to the template above using optional extras from the RSS 2.0 spec.
# app/views/posts/index.rss.builder
xml.channel do
# Required to pass W3C validation.
xml.atom :link, nil, {
:href => posts_url(:format => 'rss'),
:rel => 'self', :type => 'application/rss+xml'
}
# Feed basics.
xml.title page_title
xml.description page_title
xml.link posts_url(:format => 'rss')
# Posts.
@posts.each do |post|
xml.item do
xml.title post.title
xml.link post_url(post)
xml.pubDate post.created_at.to_s(:rfc822)
xml.guid post_url(post)
# Assuming you have an author for posts.
xml.author "#{post.author.email} (#{post.author.full_name})"
# ...and your posts have multiple tags (or categories).
post.tags.each do |tag|
xml.category tag.name, :domain => tag_url(tag)
end
end
end
end
Proper GUIDs (important)
The GUID is used by RSS readers to track which items the user has read. If this changes for a post every reader will forget it has been read. Please fix this!
A GUID shouldn’t change, we’re using the URL of the post for our GUID which is meant to be a permalink, but if we change the hostname, protocol or routes for our post this will change.
To keep your readers happy use something unique for the GUID. You don’t have to use a URL if you specify this with one more attribute in the XML.
# in app/views/posts/index.rss.builder
# Make your own random string using
# ./script/runner "puts ActiveSupport::SecureRandom.hex(20)"
xml.guid "[your string here]/posts/#{post.id}", :isPermaLink => false
Analytics
Google Feedburner lets you gather statistics on your posts and takes some of the load off your server. Once you have your Feedburner account and feed set up, leave your controller code as-is. You might want to redirect people to the Feedburner copy but then Feedburner can’t get at your feed itself. Instead change the location in the auto_discovery_link_tag to the Feedburner feed without redirecting.
GeoRSS, media etc.
RSS has some very handy extensions that some clients support. You can add location information to items using GeoRSS, you can add media such as mp3s to make podcasts using encapsulation and even video.
Here’s an example of GeoRSS.
# within your xml.item block xml.geo :lat, -43.526958 # latitude xml.geo :long, 172.744217 # longitude
Feed us
There are people that feel you shouldn’t provide feeds to your readers because it’s a bare medium. I believe sites supporting extra formats are more accessible in general.
The truth is content providers have very little control over the delivery of their information once it’s out there. Why starve readers then? Feed those who come to the table and they will return.



