How to add a dynamically generated sitemap with rails
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
config/routes.rb file defines route route and explicitly sets the format:
get 'sitemap.xml', to: 'home#sitemap', format: 'xml', as: :sitemap
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
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.