WebDevChallenges Logo
WebDevChallenges

How to add a dynamically generated sitemap with rails

Updated June 6, 21
This post shows how you can easily create a sitemap.xml file for SEO that gets generated dynamically

The sitemap.xml file on my blog is generated dynamically because I want it to include my latest posts in it.

The way I did that is that in a controller (in my case the HomeController) I added an action which initializes the @ordered_ids instance variable:

class HomeController < ApplicationController
  def sitemap
  	@ordered_ids = Post.published.order(published_at: :desc).pluck(:id)
  end
end

The config/routes.rb file defines route route and explicitly sets the format:

get 'sitemap.xml', to: 'home#sitemap', format: 'xml', as: :sitemap

The app/views/home/sitemap.xml.builder file then defines one static route and also defines routes depending on database entries (posts). These routes simply render the urls of static pages and dynamic ones (posts). Note how you can use the .xmlschema method on date objects which returns the correct format for sitemaps.

I used the .find_each method previously because I wanted to avoid loading all posts into memory at once but I noticed that you could not .order the results by published_at with .find_each.

So the new solution grabs all ids in order in the action and then grabs them by groups of 1000, loads them into memory, defines the sitemap entries and then moves on to the next 1000 as described in this stackoverflow answer.

xml.instruct! :xml, :version=>"1.0"
xml.tag! 'urlset', 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', 'xmlns:image' => 'http://www.google.com/schemas/sitemap-image/1.1', 'xmlns:video' => 'http://www.google.com/schemas/sitemap-video/1.1' do
  xml.url do
    xml.loc root_url
  end

  @ordered_ids.in_groups_of(1000, false).each do |ids|
    posts = Post.order(published_at: :desc).where(id: ids)
    posts.each do |post|
      xml.url do
        xml.loc show_post_url(post.slug)
        xml.lastmod post.updated_at.xmlschema
      end
    end
  end
end

Make sure your robots.txt file then points to that sitemap like this for search engines to find that file correctly.

Sitemap: https://webdevchallenges.com/sitemap.xml