Create a gist now

Instantly share code, notes, and snippets.

@maxivak /readme.md
Last active Nov 20, 2017

What would you like to do?
sitemap.xml for Rails 4 application

Generate sitemap.xml in Rails app

This post shows how to make sitemap.xml for your web site. The sitemap will be accessible by URL http://mysite.com/sitemap.xml

Routes

Myrails::Application.routes.draw do
  get "/sitemap.xml" => "sitemap#index", :format => "xml", :as => :sitemap

end

Controller

# app/controllers/sitemap_controller.rb

class SitemapController < ApplicationController

  def index
    respond_to do |format|
      format.xml
    end
  end

end

View

XML will be generated using XML builder. Create a view file 'sitemap/index.xml.builder' where you can use xml builder methods.

# app/views/sitemap/index.xml.builder

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', '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 base_url
  end
  xml.url do
    xml.loc base_url+'about.html'
  end
  xml.url do
    xml.loc base_url+'contacts.html'
  end
end

Generate XML dynamically

To do some refactoring let's prepare some data in controller for static pages and dynamic pages (like products).

controller:

class SitemapController < ApplicationController

  def index

    @pages = ['', 'about.html', 'contacts.html']

    @products = Product.all

    respond_to do |format|
      format.xml
    end
  end

end

change view:

# app/views/index.xml.builder

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', 'xmlns:image' => 'http://www.google.com/schemas/sitemap-image/1.1', 'xmlns:video' => 'http://www.google.com/schemas/sitemap-video/1.1' do
  xml << (render :partial => 'sitemap/common', pages: @pages)
  xml << (render :partial => 'sitemap/products', items: @products)

end

and our partials:

# app/views/sitemap/_common.xml.builder

base_url = "http://#{request.host_with_port}/"

# pages = ['about.html', 'contacts.html' ]

pages.each do |page|
  xml.url do
    xml.loc base_url+page
  end

end
# app/views/sitemap/_products.xml.builder

items.each do |item|
  xml.url do
    xml.loc product_path(item)
  end

end

williej commented Jan 26, 2017

This was awesome. Thanks !

qrush commented Feb 3, 2017

This was a ton of help. Thanks!! 👏

PatrickatPaperlessPCS commented Jul 15, 2017

Really like what you've built but wanted to make note of an issue I ran into for future users:

My sitemap was failing google tests and giving an invalid URL error for items. This was easily fixed by modifying the product partial to include the base URL:

# app/views/sitemap/_products.xml.builder

base_url = "http://#{request.host_with_port}"

items.each do |item|
  xml.url do
    xml.loc base_url+product_path(item)
  end

end

Updated to remove extra / in the base url

scolobey commented Nov 9, 2017

Found this super useful. One issue I had though. The render partial wasn't delivering the items for some reason, so it was throwing an error in app/views/sitemap/_products.xml.builder saying that items didn't exist. Fixed it by just iterating the products in the index.xml.builder itself. Lazy, but I'm moving on for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment