Private, Authenticated RSS Feeds in Rails

So, you want to allow your users to access a RSS feed of private data in their account.  Something like,

http://subdomain.yoursite.com/comments/123abc/feed.rss, where “123abc” is a secret token.

Here’s how to do this in Rails 2.1.2, though it will most likely work in other versions of Rails.  In this example, each Account has_many Comments, and we’d like to get a RSS feed of comments.

1. Create a route for the feed in your routes.rb file.

map.resources :accounts do |account|
  account.comments_feed 'comments/:token/feed.:format', :controller => 'comments', :action => 'feed', :token => nil
end

2. Create a new migration and add the feed_token to the Account.

class AddFeedTokenToAccount < ActiveRecord::Migration
  def self.up
    add_column :accounts, :feed_token, :string, :limit => 40, :default => ""
  end
 
  def self.down
    remove_column :accounts, :feed_token
  end
end

3. When a new Account is created, create the feed_token. We’ll just use a standard SHA1 hash of the current time and the account id. This should be unique enough. Let’s also create a method to validate the feed token. All of this goes in app/models/account.rb

class Account < ActiveRecord::Base
  before_create :create_feed_token
 
  def valid_feed_token?(token)
    self.feed_token == token
  end
 
  protected
 
  def create_feed_token
    self.feed_token = Digest::SHA1.hexdigest(Time.now.to_s + self.id.to_s)
  end
end

4. Add a new feed method to your Comments controller. This goes in app/controllers/comments_controller.rb

def feed
  @account = Account.find(params[account_id])
  @comments = @account.comments
  @token = params[:token]
 
  respond_to do |format|
    if @account.valid_feed_token?(@token)
      format.rss { render :layout > false }
    else
      format.rss { render :nothing > true, :status > :forbidden }
    end
  end
end

5. Create the file app/views/comments/feed.rss.builder. This is what generates the RSS feed.

xml.instruct! :xml, :version => "1.0"
xml.rss :version => "2.0" do
  xml.channel do
    xml.title "Comments"
    xml.description "A bunch of comments"
    xml.link account_comments_url(@account)
 
    for comment in @comments
      xml.item do
        xml.title comment.title
        xml.description comment.body
        xml.pubDate comment.created_at.to_s(:rfc822)
        xml.link account_comments_url(@account)
      end
    end
  end
end

6. Link to the comments RSS feed somewhere on your site. For example, somewhere in app/views/comments/index.html.erb place the following link:

<%= link_to 'Subscribe', account_comments_feed_path(@account, :format => :rss, :token => @account.feed_token)) %>
Tuesday, February 17th, 2009 Programming

4 Comments to Private, Authenticated RSS Feeds in Rails

  • Anton says:

    Hello,

    The map.resources do … seems to no longer work in rails 2.3.2, resulting in the following error:

    /usr/lib/ruby/gems/1.8/gems/actionpack-2.3.2/lib/action_controller/routing/optimisations.rb:94:in `interpolation_chunk’: wrong number of arguments (1 for 0) (ArgumentError)

    Any ideas on how this could be fixed?

    • Justin says:

      Yeah, I’m seeing this too in Rails 2.3.2. Perhaps a bug with named routes. Here’s how I’ve worked around it:

      map.connect 'comments/:token/feed.:format', :controller => 'comments', :action => 'feed'

      Now, the side effect is that you don’t have a pretty named route for your view. So, you’ll have to link to the URL using:

      <%= link_to 'Subscribe', :controller => 'comments', :action => 'feed', :token => @account.feed_token, :format => :rss %>
      • Doug says:

        I’m just a lowly noob but think you can get your pretty named rout back if you use this.

        map.resources :account, :collection => {:feed => :get}
        

        Then you can use this.

         :rss, :token => @account.feed_token) %>
        

        Great tutorial by the way. Thanks!

  • Leave a Reply

    Justin has been obsessing over writing simple Web software using Ruby on Rails since 2007. He's also an entrepreneur and Lean Startup expert. Learn more

    View Justin Britten's profile on LinkedIn

    Subscribe to Justin Britten's blog Follow Justin Britten on Twitter Network with Justin Britten on LinkedIn
     
    Prefinery: Simple, online beta management software'

    Launch a private beta for your Web application in minutes. Prefinery takes care of collecting e-mail addresses, generating invitation codes, and sending invitations for your private beta. Your customers never leave your site, and e-mail invitations are sent from your address.

    Justin is Founder and CEO of Prefinery.