feat: add sitemap functionality

- Create SitemapsController to serve sitemaps
- Configure AWS S3 storage for sitemaps
- Update routes to include sitemap paths
- Add SitemapsHelper module
- Configure SitemapGenerator with AWS adapter
- Update storage configurations for AWS

This feature adds sitemap functionality to the application, enabling search engines to discover and index its content more efficiently. It includes configuration for AWS S3 storage to host the sitemaps and updates the application's routes to serve them.
This commit is contained in:
songtianlun 2025-01-26 00:07:44 +08:00
parent ead795266e
commit 5feaee4922
8 changed files with 96 additions and 6 deletions

View File

@ -0,0 +1,33 @@
class SitemapsController < ApplicationController
def show
path = params[:path]
bucket_name =
Rails.env.production? ?
ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:aws, :bucket)) :
ENV.fetch("AWS_DEV_BUCKET", Rails.application.credentials.dig(:aws_dev, :bucket))
Rails.logger.info "Sitemap: #{path}"
begin
s3_client = Aws::S3::Client.new
response = s3_client.get_object(
bucket: bucket_name,
key: "sitemaps/#{path}"
)
expires_in 12.hours, public: true
content_type = response.content_type || "application/xml"
send_data(
response.body.read,
filename: path,
type: content_type,
disposition: "inline"
)
rescue Aws::S3::Errors::NoSuchKey
render status: :not_found
rescue Aws::S3::Errors::ServiceError => e
Rails.logger.error "S3 Error: #{e.message}"
render status: :internal_server_error
end
end
end

View File

@ -0,0 +1,2 @@
module SitemapsHelper
end

View File

@ -5,6 +5,25 @@ class RefreshSitemapWorker
host = Rails.env.production? ? "https://todayaiweather.com" : "http://127.0.0.1:3000" host = Rails.env.production? ? "https://todayaiweather.com" : "http://127.0.0.1:3000"
Rails.application.routes.default_url_options[:host] = host Rails.application.routes.default_url_options[:host] = host
SitemapGenerator::Sitemap.default_host = host SitemapGenerator::Sitemap.default_host = host
if Rails.env.production?
SitemapGenerator::Sitemap.adapter = SitemapGenerator::AwsSdkAdapter.new(
ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:aws, :bucket)),
aws_access_key_id: ENV.fetch("AWS_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws, :access_key_id)),
aws_secret_access_key: ENV.fetch("AWS_SECRET_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws, :secret_access_key)),
aws_region: ENV.fetch("AWS_REGION", "wnam"),
endpoint: ENV.fetch("AWS_ENDPOINT", Rails.application.credentials.dig(:aws, :endpoint)),
)
else
SitemapGenerator::Sitemap.adapter = SitemapGenerator::AwsSdkAdapter.new(
ENV.fetch("AWS_DEV_BUCKET", Rails.application.credentials.dig(:aws_dev, :bucket)),
aws_access_key_id: ENV.fetch("AWS_DEV_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws_dev, :access_key_id)),
aws_secret_access_key: ENV.fetch("AWS_DEV_SECRET_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws_dev, :secret_access_key)),
aws_region: ENV.fetch("AWS_DEV_REGION", "wnam"),
endpoint: ENV.fetch("AWS_DEV_ENDPOINT", Rails.application.credentials.dig(:aws_dev, :endpoint)),
)
end
SitemapGenerator::Sitemap.sitemaps_path = "sitemaps/"
SitemapGenerator::Sitemap.create do SitemapGenerator::Sitemap.create do
add root_path, changefreq: "daily", priority: 1.0 add root_path, changefreq: "daily", priority: 1.0
add cities_path, changefreq: "daily", priority: 0.9 add cities_path, changefreq: "daily", priority: 0.9
@ -32,7 +51,7 @@ class RefreshSitemapWorker
end end
# SitemapGenerator::Sitemap.ping_search_engines if Rails.env.production? # SitemapGenerator::Sitemap.ping_search_engines if Rails.env.production?
Rails.logger.info "Sitemap has been generated successfully" Rails.logger.info "Sitemap has been generated and uploaded to S3 successfully"
rescue => e rescue => e
Rails.logger.error "Error refreshing sitemap: #{e.message}" Rails.logger.error "Error refreshing sitemap: #{e.message}"
end end

View File

@ -0,0 +1,19 @@
if Rails.env.production?
Aws.config.update({
region: ENV.fetch("AWS_REGION", "wnam"),
credentials: Aws::Credentials.new(
ENV.fetch("AWS_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws, :access_key_id)),
ENV.fetch("AWS_SECRET_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws, :secret_access_key))
),
endpoint: ENV.fetch("AWS_ENDPOINT", Rails.application.credentials.dig(:aws, :endpoint))
})
else
Aws.config.update({
region: ENV.fetch("AWS_DEV_REGION", "wnam"),
credentials: Aws::Credentials.new(
ENV.fetch("AWS_DEV_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws_dev, :access_key_id)),
ENV.fetch("AWS_DEV_SECRET_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws_dev, :secret_access_key))
),
endpoint: ENV.fetch("AWS_DEV_ENDPOINT", Rails.application.credentials.dig(:aws_dev, :endpoint))
})
end

View File

@ -18,6 +18,8 @@ Rails.application.routes.draw do
get "cities/index" get "cities/index"
get "cities/show" get "cities/show"
get "home/index" get "home/index"
get "sitemaps/*path", to: "sitemaps#show", format: false
devise_for :admin_users, ActiveAdmin::Devise.config devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self) ActiveAdmin.routes(self)

View File

@ -1,5 +1,13 @@
# Set the host name for URL creation # Set the host name for URL creation
host = Rails.env.production? ? "https://todayaiweather.com" : "http://127.0.0.1:3000" host = Rails.env.production? ? "https://todayaiweather.com" : "http://127.0.0.1:3000"
Rails.application.routes.default_url_options[:host] = host
SitemapGenerator::Sitemap.adapter = SitemapGenerator::AwsSdkAdapter.new(
Rails.application.credentials.dig(:aws, :bucket),
aws_access_key_id: Rails.application.credentials.dig(:aws, :access_key_id),
aws_secret_access_key: Rails.application.credentials.dig(:aws, :secret_access_key),
aws_region: Rails.application.credentials.dig(:aws, :region)
)
SitemapGenerator::Sitemap.sitemaps_path = "sitemaps/"
SitemapGenerator::Sitemap.default_host = host SitemapGenerator::Sitemap.default_host = host

View File

@ -19,11 +19,11 @@ build:
# bucket: your_own_bucket-<%= Rails.env %> # bucket: your_own_bucket-<%= Rails.env %>
amazon_dev: amazon_dev:
service: S3 service: S3
access_key_id: <%= ENV.fetch("AWS_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws_dev, :access_key_id)) %> access_key_id: <%= ENV.fetch("AWS_DEV_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws_dev, :access_key_id)) %>
secret_access_key: <%= ENV.fetch("AWS_SECRET_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws_dev, :secret_access_key)) %> secret_access_key: <%= ENV.fetch("AWS_DEV_SECRET_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws_dev, :secret_access_key)) %>
region: <%= ENV.fetch("AWS_REGION", "wnam") %> region: <%= ENV.fetch("AWS_DEV_REGION", "wnam") %>
bucket: <%= ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:aws_dev, :bucket)) %> bucket: <%= ENV.fetch("AWS_DEV_BUCKET", Rails.application.credentials.dig(:aws_dev, :bucket)) %>
endpoint: <%= ENV.fetch("AWS_ENDPOINT", Rails.application.credentials.dig(:aws_dev, :endpoint)) %> endpoint: <%= ENV.fetch("AWS_DEV_ENDPOINT", Rails.application.credentials.dig(:aws_dev, :endpoint)) %>
amazon: amazon:
service: S3 service: S3

View File

@ -0,0 +1,7 @@
require "test_helper"
class SitemapsControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end