SitemapGenerator::CacheAdapter
A cache-based storage adapter for the sitemap_generator gem. Stores sitemaps in Rails.cache instead of the filesystem.
Why?
The default sitemap_generator adapter writes sitemaps to disk. This doesn't work well for:
- Kubernetes deployments with ephemeral pod storage
- Heroku and other read-only filesystems
- Multi-pod deployments where sitemaps need to be shared across instances
- Serverless environments without persistent storage
This adapter stores sitemaps in your Rails cache instead. When used with a database-backed cache like Solid Cache, sitemaps persist across deploys and are shared across all application instances.
Installation
Add to your Gemfile:
gem "sitemap_generator-cache_adapter"Then run:
bundle installUsage
Basic Setup
Configure sitemap_generator to use the cache adapter in config/sitemap.rb:
SitemapGenerator::Sitemap.default_host = "https://example.com"
SitemapGenerator::Sitemap.adapter = SitemapGenerator::CacheAdapter.new
SitemapGenerator::Sitemap.compress = false # Recommended for cache storage
SitemapGenerator::Sitemap.create_index = false # Single sitemap file
SitemapGenerator::Sitemap.create do
add "/about", changefreq: "monthly"
add "/contact", changefreq: "monthly"
# Add dynamic content
Post.find_each do |post|
add post_path(post), lastmod: post.updated_at
end
endServing Sitemaps (Single File)
For most sites, a single sitemap file is sufficient (up to 50,000 URLs).
Create a controller to serve sitemaps from the cache:
# app/controllers/sitemaps_controller.rb
class SitemapsController < ApplicationController
def show
xml = SitemapGenerator::CacheAdapter.fetch("sitemap.xml") do
# Load the sitemap config, which runs create and caches the result
load Rails.root.join("config", "sitemap.rb")
SitemapGenerator::Sitemap.ping_search_engines # Optional
end
if xml.present?
render xml: xml
else
head :not_found
end
end
endAdd the route:
# config/routes.rb
get "sitemap.xml", to: "sitemaps#show", defaults: { format: :xml }Note: Loading config/sitemap.rb executes the entire file, including the create block. This is how sitemap_generator is designed to work.
Serving Sitemaps (Multiple Files)
For large sites with more than 50,000 URLs, sitemap_generator creates multiple files with an index:
# config/sitemap.rb
SitemapGenerator::Sitemap.default_host = "https://example.com"
SitemapGenerator::Sitemap.adapter = SitemapGenerator::CacheAdapter.new
SitemapGenerator::Sitemap.compress = false
# Don't set create_index = false
SitemapGenerator::Sitemap.create do
# Your URLs here - will be split across multiple files if needed
endUpdate the controller to serve any sitemap file:
# app/controllers/sitemaps_controller.rb
class SitemapsController < ApplicationController
def show
filename = if params[:id].present?
"sitemap#{params[:id]}.xml"
else
"sitemap.xml"
end
xml = SitemapGenerator::CacheAdapter.fetch(filename) do
load Rails.root.join("config", "sitemap.rb")
SitemapGenerator::Sitemap.ping_search_engines
end
if xml.present?
render xml: xml
else
head :not_found
end
end
endUpdate the routes:
# config/routes.rb
get "sitemap.xml", to: "sitemaps#show", defaults: { format: :xml }
get "sitemap:id.xml", to: "sitemaps#show", defaults: { format: :xml }, constraints: { id: /[0-9]+/ }This serves:
-
/sitemap.xml- The sitemap index -
/sitemap1.xml,/sitemap2.xml, etc. - Individual sitemap files
Configuration Options
SitemapGenerator::Sitemap.adapter = SitemapGenerator::CacheAdapter.new(
cache_key_prefix: "myapp:sitemap", # Default: "sitemap_generator"
expires_in: 12.hours, # Default: 24.hours
cache_store: Rails.cache # Default: Rails.cache
)Class Methods
The adapter provides several class methods for working with cached sitemaps:
# Fetch with lazy generation
xml = SitemapGenerator::CacheAdapter.fetch("sitemap.xml") do
SitemapGenerator::Sitemap.create
end
# Read directly (returns nil if not cached)
xml = SitemapGenerator::CacheAdapter.read("sitemap.xml")
# Check existence
if SitemapGenerator::CacheAdapter.exist?("sitemap.xml")
# ...
end
# Delete a specific sitemap
SitemapGenerator::CacheAdapter.delete("sitemap.xml")
# Clear all cached sitemaps
SitemapGenerator::CacheAdapter.clear_allHow It Works
-
On cache miss: The
fetchmethod yields to the block, which callsSitemapGenerator::Sitemap.create. This triggers the adapter'swritemethod, storing the sitemap XML in the cache. -
On cache hit: The cached XML is returned immediately without regeneration.
-
Expiration: Sitemaps expire after 24 hours by default. On the next request after expiration, a fresh sitemap is generated.
This "lazy regeneration" approach means:
- No scheduled jobs required
- Sitemaps are always fresh (within the cache TTL)
- First request after expiration may be slightly slower
Cache Backend Compatibility
Works with any Rails cache backend:
- Solid Cache (recommended for Kubernetes) - Database-backed, shared across pods
- Redis - Fast, shared across pods
- Memcached - Fast, shared across pods
- Memory Store - Development/testing only (not shared)
- File Store - Single-server deployments only
Example: Kubernetes with Solid Cache
# Gemfile
gem "solid_cache"
gem "sitemap_generator"
gem "sitemap_generator-cache_adapter"
# config/environments/production.rb
config.cache_store = :solid_cache_store
# config/sitemap.rb
SitemapGenerator::Sitemap.adapter = SitemapGenerator::CacheAdapter.newWith this setup, sitemaps are stored in your database and accessible from any pod in your cluster.
Migrating from File-Based Sitemaps
- Add the gem to your Gemfile
- Update
config/sitemap.rbto use the cache adapter - Create the sitemaps controller and route
- Remove any sitemap-related cron jobs or scheduled tasks
- Add
public/sitemap*.xmlto.gitignore - Delete existing static sitemap files
Development
bundle install
bundle exec rspec
bundle exec standardrbContributing
Bug reports and pull requests are welcome on GitHub.
License
The gem is available as open source under the terms of the MIT License.