Dynamic Sitemaps on Heroku with Rails 3

I needed to add a sitemap for a project that was hosted on Heroku, which I was hoping to be as simple as gem install [some sitemap gem] as it seems to be with 90% of rails development. Such is not the case, however.

Difficulty? Heroku doesn’t let you write to their filesystem, outside of the /tmp directory. Also, I haven’t looked into running background processes (like cron) on Heroku, but that seemed to be a whole thing so I figured there had to be a dynamic way to do this. There’s gem for creating a sitemap (sitemap_generator by kjvarga), but you need to save the file on S3 and this is for a client that doesn’t have an S3 account already and I figured that seemed a bit excessive for what is basically one text file sitting in a root folder.

Here’s my solution. It’s mostly based on this typo-riffic Dynamic50 article and a routing tip from Bill Rowell. It ‘just works’ and updates dynamically on Heroku and is totally hands off unless you change your site structure. Also for those of you using Google Webmaster Tools, this will put the sitemap.xml file in the default location.

First, add this to your routes.rb file:

resources :sitemaps, :only => :show
match "/sitemap.xml", :controller => "sitemaps", :action => "show", :format => :xml

Then create a sitemaps_controller.rb file and use this (change accordingly):

 
class SitemapsController < ApplicationController
  respond_to :xml
  caches_page :show

  def show
    @protocols = Protocol.where(:is_approved => true)
    @other_routes = ["/","/about"]
    respond_to do |format|
     format.xml
    end
  end
end

And then create views/sitemaps/show.xml.builder and add:

base_url = "http://#{request.host_with_port}"
xml.instruct! :xml, :version=>'1.0'
xml.tag! 'urlset', 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9' do
  @other_routes.each do |other|
    xml.url {
      xml.loc("http://example.com#{other}")
      xml.changefreq("daily")
    }
  end
  @protocols.each do |p|
    xml.url {
      xml.loc("http://example.com/protocols/#{p.id.to_s}")
      xml.changefreq("daily")
    }
  end
end

You’ll want to edit this to match any changes you made to the controller file.

And that’s it. Thanks to those mentioned above.

If you have any tips or if I did something stupid, please let me know. Thanks!

2 Responses to “Dynamic Sitemaps on Heroku with Rails 3”

    • doug

      Thanks man! I appreciate it. I’ve been bogged down with a lot of PHP lately, so I haven’t done much in RoR. Glad i was able to help someone out