0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

gem sitemap-generatorの使い方

Posted at

はじめに

業務で顧客からの依頼でsitemap.xmlの作成を依頼されました。sitemap.xmlの仕様自体いまいち理解していなかった+いくつかハマりポイントがあったので、今後のメモ代わりに調査結果・実装内容を書き留めておきます。

使用技術

  • FW: Ruby on Rails
  • gem: sitemap-generator
  • AWS: S3

主な内容

  • sitemap.xml.gzを複数ファイルに分けて作成する方法
  • S3連携の補足
    • S3アップロードが必要な場合
    • S3アップロード時の選択肢
    • S3アップロード時の注意点
  • pingの仕様
  • robots.txtの動的な記述

sitemap-generatorについて

基本的な設定などについては以下の参考記事が抜群にわかりやすいので、こちらをご参照下さい。
【Rails】 sitemap_generatorを使ってサイトマップを作成しよう

※本記事では上記を前提として、その上でハマった点とその解消方法に焦点を当てます

sitemap.xml.gzを複数ファイルに分けて作成する方法

今回の要件に、すべてを1つのsitemap.xml.gzにまとめるのではなく、記事はarticles-sitemap.xml.gzに、静的ページはstatics-sitemap.xml.gzに…というように種類ごとにサイトマップをまとめて作成してほしい、というものがありました。

日本語記事は見つからなかったのですが、READMEの記述がわかりやすかったです。
sitemap-generator README

参考までに記載方法は以下のようになります。

SitemapGenerator::Sitemap.default_host = "http://www.example.com"
SitemapGenerator::Sitemap.create do
  group(:filename => 'article-details') do
    Article.find_each do |article|
        add article_path(article), lastmod: article.updated_at, priority: 0.7
    end
  end
end

SitemapGenerator::Sitemap.create do
  group(:filename => 'statics') do
    add '/about'
    add '/contact'
  end
end

bundle exec rake sitemap:refreshなどでsitemapを生成すると以下のようなファイルが作成されます。

  • article-details.xml.gz
  • statics.xml.gz
  • sitemap.xml.gz

このうち、sitemap.xmlはインデックス用のxmlでarticle-details.xmlstatics.xml.gzの場所をクローラーに伝えてくれます。
sitemapの仕様を決めているsitemap.orgの公式ドキュメントでは、インデックスファイルの場合はsitemapindexタグの使用が必須と記載されていますが、sitemap-generatorで生成されるインデックスファイルはちゃんとこの仕様に則っていました。

参考: sitemap.orgドキュメント

S3連携の補足

冒頭に参考を示したpikawakaさんの記事にもS3設定の方法が記載されていますが、S3アップロードの必要性やオプション、S3側の設定などについてハマったので対策をまとめます。

S3アップロードが必要な場合

herokuのようなPaaSでデプロイしている場合には必要だと思います。
EC2などの場合には設定によりそうです。

具体的には、例えばherokuの場合、以下のような仕様があるためsitemap.xml.gzの配信には向いていません。

つまりデプロイ後にheroku内でコマンドを実行して生成されたファイルは削除されます。
dyno再起動の時間を設定・heroku schedulerで毎日再起動直後に生成するようなこともできなくはないかもしれませんが、手間や不確実性を考えるとS3のほうが合理的だと思います。

S3アップロード時の選択肢

pikawakaさんの記事ではS3Adapter(内部的にはFog)を使用していますが、他にも以下の選択肢があります。
個人的に特に活用できそうだと感じたものは以下です。

  • SDK
  • CarrierWave

特にアップローダーとしてCarrierWaveが設定済のプロジェクトであれば、わざわざS3の情報を環境変数から取ってくるコードを書かなくて良くなるので、CarrierWaveでいいんじゃないかと思いました。

CarrierWaveと組み合わせて使うには以下のWIKIがわかりやすかったです。
GitHubリポジトリ内のWIKI

S3アップロード時の注意点

S3周りだと以下でハマりました。

  1. ACLs周りのエラー
  2. パブリックアクセスに対する公開設定

1.ACLs周りのエラー

今S3のIaCで「AccessControlListNotSupported: The bucket does not allow ACLs」というエラーが出たならそれは2023年4月に行われたS3の仕様変更が原因かもしれない

要するに、S3の仕様がかわり、ACLs(アクセスコントローラーリスト)がデフォルトで無効になったということです。
ACLsはS3に保存されるファイルごとに、公開・非公開を制御しています。
これが無効だと、ACLsを設定しようとするリクエストに対して400番が返るようになり、落ちます。

sitemap-generatorの文脈でいうと、SDKAdapterを使用する際のaclオプションの設定や、S3Adapterをinitializeする際にpublic: falseを明示しないとエラーがでます。

※以下の34〜35行目あたりでS3Adapterをデフォルトでpublic: trueにしている記述があります
S3Adapterの実装

2. パブリックアクセスに対する公開設定

これもACLsまわりの設定が原因です。
S3はデフォルトでパブリックアクセスがすべて無効になっています。
なので適切に設定を変えないと、クローラーからのアクセスも拒否されます。

方法としてACLを有効にするという手段もありますが、公式がデフォルトで無効にしているのでバケットポリシーで特定のパスだけパブリックアクセスを許可するのが正しいと考えています。

やり方は以下のとおりです。

  1. S3 コンソールでバケットを開き、「アクセス許可」 → 「ブロックパブリックアクセス (bucket settings)」 を確認
  2. 以下のチェックを外す
    • 新しいパブリックバケットポリシーをブロック
    • 任意のパブリックバケットポリシーをブロック
  3. 「アクセス許可」 → 「バケットポリシー」のセクションに移動し、編集ボタンを押下
  4. 以下を参考にバケットポリシー用のJSONを記述
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowPublicReadSitemapsOnly",
          "Effect": "Allow",
          "Principal": "*",
          "Action": "s3:GetObject",
          "Resource": "arn:aws:s3:::bucket-name/sitemaps/*"
        }
      ]
    }
    
    ※上記の場合sitemap-generator側で以下のように記述しています。
    SitemapGenerator::Sitemap.sitemaps_path = "sitemaps/"
    

S3のバケットポリシーの記述方法はいろいろ設定できるようなので、AI活用しつつ、公式ドキュメントでエビデンスを確認するのが良さそうです。
AWS公式ドキュメント

pingの仕様

bundle exec rake sitemap:refreshを実行すると、pingが送信される、
と公式ドキュメントには記載があり、実装もそうなっていそうですが、ちょっと注意が必要そうです。
sitemap-generator公式ドキュメント: 検索エンジンへのping

まず、デフォルトでは送信先の検索エンジンが設定されていないので、送信したい場合には検索エンジンの指定のためのコードを記述する必要があります。

次に、そもそもGoogleやBingはpingを受け付けていません。
Googleのお知らせ
Bingのsitemap仕様

なので、設定自体は可能であっても実務的には意味はないと考えています。

robots.txtの動的な記述

ステージング環境を使用している場合、ステージングと本番でrobots.txtの出し分けを行う必要があります。(Basic認証を入れるなどしていれば不要ですが)
方法はいろいろあると思うのですが、個人的にはコントローラー出だし分けるのがシンプルで良かったです

# routes.rb
Rails.application.routes.draw do
  # クローラー向け
  get '/robots.txt' => 'robots#show'
  .
  .
  .
end
# robots_contoroller.rb
class RobotsController < ActionController::Base
  def show
    if ENV['RAILS_ENV'] == 'production'
      content = <<~TXT
        User-agent: *
        Sitemap: https://bucket-name.s3.region.amazonaws.com/sitemaps/sitemap.xml.gz
      TXT
    else
      content = <<~TXT
        User-agent: *
        Disallow: /
      TXT
    end

    render plain: content, content_type: 'text/plain'
  end
end

以上です!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?