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!