静的OGPの設定を、meta-tagsで動的OGPの設定に上書きし反映させる方法

こんにちは、ぱきらと申します。
プログラミングスクール『RUNTEQ』に未経験で入学し卒業たばかりの初学者です。
　
以前・個人開発をした際
静的OGPは設定できたけども、動的OGPを本番環境で反映させるのに苦戦しました。
今回は、**`meta-tags`というGemの`set_meta_tags`メソッドを使って**
**`設定している静的OGP画像`を、`動的OGP用の画像`に上書きしてくれる事案を記載します！**

https://github.com/kpumuk/meta-tags

- Rails 7.1.3.1、　Ruby 3.2.3.、PostgreSQLを使っています


　
## 導入や設定が済んでいる前提のもの
- **`db/schema.rb`に、`生成と保存をした動的OGP画像を格納するカラム`を追加**
    - 私の場合は、`Posts`テーブルに`ogp`カラムを追加しました
        ```bash:ターミナルでマイグレーションファイルを生成
        rails generate migration AddOgpToPost ogp:string
        ```
        ```ruby:db/migrate/xxx_add_ogp_to_post.rb（生成されたマイグレーションファイル）
        class AddOgpToPost < ActiveRecord::Migration[7.1]
          def change
            add_column :posts, :ogp, :string
          end
        end
        ```
        ```diff_ruby:app/models/post.rb に追記
        class Post < ApplicationRecord
          ...
          belongs_to :user
        + mount_uploader :ogp, PostOgpUploader # UploaderをPost.ogpに紐付け
        end
        ```
        ```bash:ターミナルでマイグレを実行
        rails db:migrate
        ```
        ```diff_ruby:db/schema.rb
        ActiveRecord::Schema[7.1].define(version: xxxx_xx_xx_xxxxxx) do
          ...
          create_table "posts", force: :cascade do |t|
            ...
        +   t.string "ogp"
            ...
          end
        ```
　
- **使う４つの Gem を導入**
    ```diff_ruby:Gemfile に追記
      ...
    + gem "mini_magick" # 動的OGP画像を生成する
    + gem "meta-tags", require: "meta_tags" # 特定のページのURLをシェア時にOGP画像に反映させる
    + gem "carrierwave", "~> 3.0"
    + gem "fog-aws" # AWS用のfog
      ...
    ```
    ```bash:ターミナルでインストールを実行
    bundle install
    ```
  - **mini_magick**の導入に参考にさせていただいた記事
    - [【動的OGP】 Rails7, Dockerを使ってXシェアを実装する](https://zenn.dev/yukimura_n/articles/1007c5dbedebc1)
  - **carrierwave**（3.0ver）の導入に参考にさせていただいた記事  
    - [Heroku x Railsで動的にOGP画像生成してみる](https://www.mof-mof.co.jp/tech-blog/heroku-rails-imagemagick)
　
- **生成した動的OGP画像を、AWS S3 のバケットに保存する設定**
    ```diff_ruby:app/uploaders/post_ogp_uploader.rb を生成し、以下のように追記
    class PostOgpUploader < CarrierWave::Uploader::Base
    
    + if Rails.env.production?
    +   storage :fog  # 本番環境ではAWS S3のバケットに保存
    + else
    +   storage :file # 開発環境ではpublicディレクトリに保存
    + end
    
    + def store_dir
    +   "AWS S3のバケットに保存する際のディレクトリ名を指定"
    + end

    end
    ```
  - そして、👇の記事を参考にさせていただき     `config/initializers/carrierwave.rb`などを生成し、設定しました

https://zenn.dev/mockey/articles/daf80384bf18d2



# meta-tagsの`set_meta_tags`メソッドで静的OGPの設定を 動的OGP画像の設定に上書きする方法
### ❶ 動的OGPを適応したいコントローラー内のアクションに追記
- 私の場合は投稿データを使う、ログイン不要のアクションに追記しました
    ```diff_ruby:xxx_controller.erb
      ...
      def 動的OGPを適応したいアクション名
        @post = Post.find(params[:id])
    +   if @post  # 投稿が存在する場合
    +     # 保存した動的OGP画像のURLを ogp_image_url に代入
    +     ogp_image_url = OGPを生成と保存するメソッド名(@post)   
    +     set_meta_tags(og: { image: ogp_image_url }, twitter: { image: ogp_image_url }) 
    +   end

      private
    
    + def OGPを生成と保存するメソッド名(post)
    +   begin
    +     image_data = OgpCreator.build("#{post.user.name}さんが#{post.title}を投稿しました")
    +     post.update!(ogp: image_data) # 生成した動的OGP画像を保存
    +     post.ogp.url   # 保存された動的OGP画像のURL
    +   rescue StandardError => e
    +     Rails.logger.error("動的OGP画像の生成または保存に失敗: #{e.message}")
    +     nil
    +   end
    + end
      ...
    ```
    - 👆**上記の`set_meta_tags`メソッド**は、 `meta-tags`というgemのメソッドで  
      👇以下の静的OGPの設定にある`og:`と`twitter:`内の`image:`内の値を、動的OGP用に上書きしてくれます
        ```ruby:app/helpers/application_helper.rb（静的OGPの設定）
        module ApplicationHelper
            def default_meta_tags
              {
                site: 'サイト名', ...
                og: { ...
                  image: image_url('静的OGP画像名')},  # 動的OGPではここを上書きしたい
                twitter: { ... # X(旧Twitter)にもOGPを反映させたいなら必要な記載
                  image: image_url('静的OGP画像名')}   # 動的OGPではここを上書きしたい
              }
            end
        end
        ```
    - **`OgpCreator.build`** という記載は  
    👇以下の記事を参考に生成した`app/controllers/concerns/ogp_creator.rb`を使います（今回の記事では詳細は割愛します）

https://www.mof-mof.co.jp/tech-blog/heroku-rails-imagemagick#:~:text=ogp%2C%20UserOgpUploader-,OGP%E7%94%BB%E5%83%8F%E7%94%9F%E6%88%90%E5%87%A6%E7%90%86,-OGP%E3%81%AF%E3%83%99%E3%83%BC%E3%82%B9

　
### ❷ ビューで`meta_tags`を呼び出す
```diff_ruby:app/views/layouts/application.html.erbに追記
  <head>
    ...
+   # 静的OGP(特定のページのみ動的OGPを適応)
+   <%= display_meta_tags(default_meta_tags) %>
  </head>
```
- 追記できたら、`動的OGPを適応したいアクション`のページの検証ツールの要素を見てみましょう！
  `og:`と`twitter:`内の`image`に
  `AWS S3バケットに保存された動的OGP画像URL`（下記の画像の青く囲った箇所）が渡されましたね
[![Image from Gyazo](https://i.gyazo.com/cc0a7ada431288f7e1a22fb4ad38b8aa.png)](https://gyazo.com/cc0a7ada431288f7e1a22fb4ad38b8aa)

　
### ❸ 動的OGPが適応されたか確認
- `AWS S3バケットに保存された動的OGP画像URL`(上記の画像の青く囲った箇所)にアクセスしたら、動的OGP画像が表示された🎊
  [![Image from Gyazo](https://i.gyazo.com/6b9d14a246afea88e40dd273a21fe73c.png)](https://gyazo.com/6b9d14a246afea88e40dd273a21fe73c)
- `動的OGPを適応したいアクション`のページのURLを、[OGP確認ツール](https://ogp.buta3.net/)に入力すると動的OGP画像が表示された🎊
  [![Image from Gyazo](https://i.gyazo.com/77ce0f696ddcc8c20edf838032008662.png)](https://gyazo.com/77ce0f696ddcc8c20edf838032008662)
- `動的OGPを適応したいアクション`のページのURLを、Xにシェアすると動的OGP画像が表示された🎊
  [![Image from Gyazo](https://i.gyazo.com/4ef82d35343a0f6f8e940874e73426ad.png)](https://gyazo.com/4ef82d35343a0f6f8e940874e73426ad)

**👏✨これで完成です！！👏✨**
_____
## X（旧Twitter）で動的OGP画像が表示されない場合の要因
- `app/assets/images`に入れてる動的OGP用の画像のサイズが大きい
- キャッシュの問題
  - Xは７日ほどキャッシュが残るので、キャッシュが消えれば反映される可能性がある
- `動的OGPを反映させたい特定のページ(URL)`が  
  **ログインしないとアクセスできないURLだった場合、今回の記事の方法だけでは反映できません**
  - 本来、XにシェアされたURLは、**Xのbotさん🤖**がアクセスしに行き
    meta-tagsに渡されてる`AWS S3バケットに保存した動的OGP画像URL`を認識し、Xに動的OGP画像を表示してくれます。
  - ただ、その`動的OGPを反映させたい特定のページ(URL)`が、ログインしないとアクセスできないURLだった場合は
    **Xのbotさん🤖はログインできず・アクセスできない**為、XにURLをシェアしても動的OGP画像が反映できないわけです。
  - この場合の実装方法は、私は実行していないので知見はありません。申し訳ありません、調べてみて下さい🙇‍♀️
　 

### 終わりに
はじめに記載した通り、私はプログラミングの初学者です。
この記事に間違った記載や、アドバイスがある方は
是非ともコメントで教えていただけると、大変助かります。
読んでいただき、ありがとうございました🙇‍♀️