[Rails] sitemap_generator使ってsitemap作成、GAEにデプロイ

## sitemapとは
GoogleやYahooなどの検索エンジンに、サイトの登録をする際に必要なファイル。
Search Console(Google検索登録サービス)で、聞かれるやつ。
中身は主に、検索で表示させたいページの情報が載っている。

## sitemap_generator追加
`Gemfile`に追記。※ Githubは[こちら](https://github.com/kjvarga/sitemap_generator)
    
```ruby:Gemfile
gem 'sitemap_generator'
```

`gem`をインストール

```shell
$ bundle install
```

## sitemap.rbを作成

下記コマンドを実行すると、`config/sitemap.rb`が生成される。

```shell
$ rails sitemap:install
```
生成された、`config/sitemap.rb`を編集していく。
`SitemapGenerator::Sitemap.default_host `は、本番でのhostを入れる。
`SitemapGenerator::Sitemap.create`の中に、検索に登録したいページを記述していく。

```ruby:config/sitemap.rb
require 'rubygems'
require 'sitemap_generator'

SitemapGenerator::Sitemap.default_host = "http://www.example.com"
SitemapGenerator::Sitemap.create do
  add '/', changefreq: 'weekly', priority: 0.9
  add '/about', changefreq: 'weekly', priority: 0.5

  User.all.each do |user|
    add user_path(user), lastmod: spot.updated_at
  end
end
```
ローカルで、実行してみる。

```shell
$ rails sitemap:refresh
```
sitemapの更新と検索エンジンに通知が走る。
検索エンジンに、通知したくない場合は、`no_ping`をつける。

```shell
$ rails sitemap:refresh:no_ping
```

実行すると、`public/sitemap.xml.gz`が生成されていることが確認できる。
http://localhost:3000/sitemap.xml.gz よりダウンロードできる。

## [GCP] cron job 設定

`sitemap.xml.gz`はUserが作成されるたびに、更新をする必要があるので、`cron job`にて一日ごとに定期実行する。
そのためのエンドポイントを追加。

```ruby:cron_jobs_controller.rb
class CronJobsController
  def refresh
    logger.info `bundle exec rails sitemap:refresh`
    head :ok

  rescure StandardError => e
    logger.error e.full_message
    head :internal_server_error
  end
end
```

```ruby:routes.rb
Rails.application.routes.draw do
  ...

  resources :sitemaps, only: [:index]
end
```

`cron.yaml`に設定を追加。

```yaml:cron.yaml
cron:
- description: sitemap
  url: /cron_jobs/sitemaps
  timezone: Asia/Tokyo
  schedule: every day 03:00
```

`cron jobs`の設定をデプロイ。

```
$ gcloud app deploy cron.yaml --project=target-project
```

これで`cron jobs`による定期実行の設定が完了です。

## [GCP] sitemap.xml.gzをGCSに上げるよう設定
本番環境のGAEでは、スケールアウトのため3インスタンスを扱っている。
このため、動的にファイルを生成してインスタンスに置いた場合1/3の確率でしかファイルがヒットしない。

そもそも`PaaS`環境下でインスタンスに生成ファイルを置くことがアンチパターンである。
外部ストレージ（GCS）にアップすることが良い。
`Computed Engine`などを使っている場合は問題ない。

`sitemap_generator`のドキュメントにあるように、GCSの設定を`config/sitemap.rb`に追加する。

> SitemapGenerator::GoogleStorageAdapter
Uses Google::Cloud::Storage to upload to Google Cloud storage.
You must require 'google/cloud/storage' in your sitemap config before using this adapter.
An example of using this adapter in your sitemap configuration with options:

by https://github.com/kjvarga/sitemap_generator#upload-sitemaps-to-a-remote-host-using-adapters

```ruby:config/sitemap.rb
require 'rubygems'
require 'sitemap_generator'
require 'google/cloud/storage'

SitemapGenerator::Sitemap.default_host = ENV['BASE_URL']
SitemapGenerator::Sitemap.sitemaps_host = "https://storage.googleapis.com/#{ENV['GOOGLE_BUCKET']}"
SitemapGenerator::Sitemap.adapter = SitemapGenerator::GoogleStorageAdapter.new(
  credentials: ENV['GOOGLE_CREDENTIAL'],
  project_id: ENV['GOOGLE_PROJECT_ID'],
  bucket: ENV['GOOGLE_BUCKET']
)
SitemapGenerator::Sitemap.create do
  add '/', changefreq: 'weekly', priority: 0.9
  add '/about', changefreq: 'weekly', priority: 0.5

  User.all.each do |user|
    add user_path(user), lastmod: spot.updated_at
  end
end
```

`https://domain/sitemap.xml.gz`でアクセスが来た際に、GCS上の`sitemap.xml`にredirectさせるルーティングを追加。

```ruby:routes.rb
Rails.application.routes.draw do
  ...

  get '/sitemap.xml.gz', to: redirect("https://storage.googleapis.com/#{ENV['GOOGLE_BUCKET']}/sitemap.xml.gz", status: 301)
end
```

これで、再度GAEのインスタンスデプロイをすれば設定完了。
`cron job`が動いた後に、`https://domain/sitemap.xml.gz`でアクセスすれば、`sitemap.xml.gz`をダウンロードできる。

## 参考
- https://github.com/kjvarga/sitemap_generator
- https://cloud.google.com/appengine/docs/flexible/nodejs/scheduling-jobs-with-cron-yaml
- https://www.anegron.site/2020/05/23/sitemap-for-your-rails-app-with-google-cloud-storage/