feat: add sitemap management feature

- Implement index action to list sitemaps
- Create view for displaying sitemaps with details
- Add helper method for generating sitemap URLs
- Enhance error handling for S3 service errors

This commit introduces a new feature for managing sitemaps in the application. It includes an index view that lists all available sitemaps with their last modified date and size, along with a link to view each sitemap. The error handling for S3 interactions has also been improved to log errors and return appropriate responses.
This commit is contained in:
songtianlun 2025-02-24 17:28:21 +08:00
parent 2a360a6875
commit 3ae870047a
4 changed files with 106 additions and 6 deletions

View File

@ -1,16 +1,24 @@
class SitemapsController < ApplicationController
include SitemapsHelper
before_action :set_bucket_name
def index
@sitemaps = list_sitemaps
respond_to do |format|
format.html
format.xml { render_sitemap_index }
end
rescue Aws::S3::Errors::ServiceError => e
Rails.logger.error "S3 Error: #{e.message}"
render status: :internal_server_error
end
def show
path = params[:path]
bucket_name =
Rails.env.production? ?
ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:minio, :bucket)) :
ENV.fetch("AWS_DEV_BUCKET", Rails.application.credentials.dig(:minio_dev, :bucket))
Rails.logger.info "Sitemap: #{path}"
begin
s3_client = Aws::S3::Client.new
response = s3_client.get_object(
bucket: bucket_name,
bucket: @bucket_name,
key: "sitemaps/#{path}"
)
@ -30,4 +38,49 @@ class SitemapsController < ApplicationController
render status: :internal_server_error
end
end
private
def set_bucket_name
@bucket_name = Rails.env.production? ?
ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:minio, :bucket)) :
ENV.fetch("AWS_DEV_BUCKET", Rails.application.credentials.dig(:minio_dev, :bucket))
end
def s3_client
@s3_client ||= Aws::S3::Client.new
end
def list_sitemaps
response = s3_client.list_objects_v2(
bucket: @bucket_name,
prefix: "sitemaps/"
)
response.contents.map do |object|
{
key: object.key.sub("sitemaps/", ""),
last_modified: object.last_modified,
size: object.size,
url: sitemap_url(object.key.sub("sitemaps/", ""))
}
end.reject { |obj| obj[:key].empty? }
end
def render_sitemap_index
base_url = "#{request.protocol}#{request.host_with_port}"
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
xml.sitemapindex(xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9") do
@sitemaps.each do |sitemap|
xml.sitemap do
xml.loc "#{base_url}/sitemaps/#{sitemap[:key]}"
xml.lastmod sitemap[:last_modified].iso8601
end
end
end
end
render xml: builder.to_xml
end
end

View File

@ -1,2 +1,5 @@
module SitemapsHelper
def sitemap_url(filename)
"/sitemaps/#{filename}"
end
end

View File

@ -0,0 +1,43 @@
<%# app/views/sitemaps/index.html.erb %>
<div class="container mx-auto px-4 py-8">
<div class="max-w-4xl mx-auto">
<h1 class="text-3xl font-bold mb-6">Sitemaps Index</h1>
<div class="bg-white rounded-lg shadow overflow-hidden">
<div class="overflow-x-auto">
<table class="table w-full">
<thead>
<tr>
<th>Filename</th>
<th>Last Modified</th>
<th>Size</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% @sitemaps.each do |sitemap| %>
<tr class="hover">
<td><%= sitemap[:key] %></td>
<td><%= sitemap[:last_modified].strftime("%Y-%m-%d %H:%M:%S") %></td>
<td><%= number_to_human_size(sitemap[:size]) %></td>
<td>
<%= link_to "View", sitemap[:url],
class: "btn btn-sm btn-primary",
target: "_blank" %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
<div class="mt-6 bg-base-200 p-4 rounded-lg">
<h2 class="text-xl font-semibold mb-2">For Search Engines</h2>
<p class="mb-2">Sitemap Index URL:</p>
<code class="block bg-base-300 p-2 rounded">
<%= sitemaps_url(format: :xml) %>
</code>
</div>
</div>
</div>

View File

@ -25,6 +25,7 @@ Rails.application.routes.draw do
get "cities/index"
get "cities/show"
get "home/index"
get "sitemaps", to: "sitemaps#index"
get "sitemaps/*path", to: "sitemaps#show", format: false
get "feed", to: "rss#feed", format: "rss", as: :rss_feed