【Rails】 meta-tags と Cloudinary を使って動的にOGP画像を作る

今回[「Yuppeing-App」](https://yuppeing-app.herokuapp.com/)という質問箱風のアプリを作ったのですが、シェアボタンからTwitterにシェアした時に、もらった質問の文をTwitter Card に、その回答をTweet文にするという機能を実装したので、まとめてみました。

出来上がりはこんな感じです🔽
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Progate と Railsチュートリアルです😊詳しくは固定Tweetにある note にも書いてあるのですが、楽し過ぎてハマりました😍将来の夢は特にないのですがw、自分が楽しみながら誰かの役に立てれば最高だな！！と思っています☺️ <a href="https://t.co/6JDblGZuVL">https://t.co/6JDblGZuVL</a> <a href="https://twitter.com/hashtag/YuppeingApp?src=hash&amp;ref_src=twsrc%5Etfw">#YuppeingApp</a></p>&mdash; Yuppy 🔛 Rails💎 (@Yuppyhappytoyou) <a href="https://twitter.com/Yuppyhappytoyou/status/1193829947489472512?ref_src=twsrc%5Etfw">November 11, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


### 環境

```ruby:Gemfile
ruby '2.6.2'

gem 'rails', '6.0.0'
```
heroku へのデプロイ済みです。

## デフォルトの meta 情報を設定する

### 1.`meta-tags` gem をインストール

この gem を入れると、head タグ内の meta タグをすっきりと整理することができます。


```ruby:Gemfile
gem 'meta-tags'
```
追加して`bundle install`します。

### 2.`default_meta_tags`を設定

```ruby:app/helpers/application_helper.rb
module ApplicationHelper
  def default_meta_tags
    {
      site: 'Yuppeing App',
      title: 'Yuppyに質問してみよう！',
      reverse: false,
      charset: 'utf-8',
      description: 'Yuppy専用質問箱風アプリです。Yuppyに質問してみよう！',
      keywords: 'Yuppeing App, Yuppy, yuppy, Yuppyに質問',
      canonical: 'https://yuppeing-app.herokuapp.com/',
      separator: '|',
      icon: [
        { href: image_url('favicon.ico') }
      ],
      og: {
        site_name: :site,
        title: :title,
        description: :description,
        type: 'website',
        url: :canonical,
        image: image_url('ogp.png'),
        locale: 'ja_JP',
      },
      twitter: {
        card: 'summary',
        site: '@YuppyHappyToYou',
      }
    }
  end
end
```

| 値 | 設定するもの |
|   :-:  |   :-:  |
| site  | サイト名 |
| title | タイトル |
| reverse | trueで、タイトル・サイト名の表示順が逆になる |
| charset | 文字コード |
| description | ページの説明 |
| keywords | ページのキーワード 「,」区切りで設定
| canonical | リンクタグをフルパスで設定 |
| separator | ウェブサイト名とページタイトルを区別するテキスト |
| icon | favicon、apple用アイコンの設置 |
| og:site_name | サイト名 (siteと同じなら:site) |
| og:title | 各ページのタイトル |
| og:description | ページの説明 |
| og:type | ページの種類 ‘website’, ‘article’, ‘blog’など |
| og:url | URLを設定 |
| og:image | シェア用の画像を設定 |
| og:local | リソースの言語を設定 |

[meta-tags gem の README](https://github.com/kpumuk/meta-tags) や、[OGP設定に関する記事](https://marketingnative.jp/how-to-use-open-graph-protocol/)を見ながらお好みで値を設定してみてください。

```ruby:app/views/layouts/application.html.erb
# headタグ内に置く
<%= display_meta_tags(default_meta_tags) %>
```

## 動的に OGP 画像を表示させる

使用方法のイメージは、背景画像を Cloudinary に保存、テキストは動的に`@post.content` を取り、背景画像の上に載せて表示させたものをOGP画像として設定します。

まず使用する gem をインストールしておきます。

```ruby:Gemfile
gem 'cloudinary'
gem 'carrierwave'
```

```
$ bundle install
```

### 1. heroku に Cloudinary を アドオンする

[HEROKU公式サイト](https://elements.heroku.com/addons/cloudinary)に従い、以下コマンドでアドオンを追加します。

```
 $ heroku addons：create cloudinary：starter
```
Starter は Cloudinary のフリープランの名称です。

※HEROKU のダッシュボードの「Configure Add-ons」からも追加できます。
<img width="579" alt="スクリーンショット 2019-11-13 12.10.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/bc693511-abc2-5d43-aec4-e5466cfb4993.png">

### 2. Cloudinary の設定

HEROKU にアドオン追加されたのが確認できたら、クリックして Cloudinary を開きます。

<img width="576" alt="スクリーンショット 2019-11-13 12.22.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/34e272c0-5063-2cbd-a7b8-2465ee81057e.png">

言語選択では Rails を選びます。

ダッシュボードの **Account Details** のところの yml をダウンロードします。
<img width="816" alt="スクリーンショット 2019-11-13 12.43.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/e383842f-a498-e427-789d-04d462ae5d5e.png">

ダウンロードしたファイルを config ディレクトリに配置します。
<img width="171" alt="スクリーンショット 2019-11-13 12.56.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/b6ebf1c9-54da-486e-fa49-921a902cdd54.png">

この後、記載されている情報は**環境変数に設定**します。このまま公開することは絶対にしないで下さい。

#### 環境変数の設定

```ruby:Gemfile
gem 'dotenv-rails'
```

`dotenv-rails`を使う方は.env ファイルを作成し、以下のように書き設定します。

```ruby:.env
CLOUDINARY_CLOUD_NAME = 取得したcloud_name
CLOUDINARY_API_KEY    = 取得したapi_key
CLOUDINARY_API_SECRET = 取得したapi_secret
```
その他、任意の方法で各自環境変数に設定してください。

#### heroku にも環境変数を登録
heroku で複数のアプリを所持されている方はアプリ名の指定をして設定します。

```ruby
$ heroku config:set CLOUDINARY_CLOUD_NAME = 取得したcloud_name --app "指定したアプリ名"
```

または、HEROKU ダッシュボードの Settings の「Config Vars」からも簡単に設定できるのでお好きな方で。
<img width="575" alt="スクリーンショット 2019-11-13 17.15.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/a5b643e1-7ffe-1e84-56e6-05be1aaabdbe.png">

### 3. 個別のOGP画像用URLを編集する

Cloudinary の Media Library にドラッグ＆ドロップでOGP画像の背景となる画像を追加します。
<img width="767" alt="スクリーンショット 2019-11-13 18.49.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/d8a094df-e26e-b94d-7354-44cbfea38a27.png">

リンクをクリックしてコピーします。

そのリンクの`upload/`より後ろに追加情報を入れていきます。

```
l_text:フォントの種類_フォントサイズ_ウェイト:背景画像に重ねるテキスト,その他オプション
```

参考: [Cloudinaryの画像変換を極める](https://qiita.com/kanaxx/items/d098ef82a19ff1061f46)

以下が、私のURLです。

```
https://res.cloudinary.com/私のCLOUDINARY_CLOUD_NAME/image/upload/l_text:Sawarabi%20Gothic_18:#{@post.content},co_rgb:6d3e12,w_380,c_fit/v1573396517/ogp-bg_merhm7.png
```

Sawarabi Gothic (スペースは%20に置き換えます)フォントの18px、配置するテキストはPostモデルの content (質問文)、フォントカラーは茶色を指定しました。
[Google フォント](https://fonts.google.com/?subset=japanese)から選べるそうなのですが、Sawarabi 系しか動作してくれませんでした😥

### 4. 個別のOGP画像用URLを set する

`set_meta_tag`を好きなページに配置して、先ほど作ったOGP画像用URLを埋め込みます。

```ruby:app/views/posts/show.html.erb
<% if @replied %>
  <% set_meta_tags og: {image: "https://res.cloudinary.com/私のCLOUDINARY_CLOUD_NAME/image/upload/l_text:Sawarabi%20Gothic_18:#{@post.content},co_rgb:6d3e12,w_380,c_fit/v1573396517/ogp-bg_merhm7.png" },
              twitter: {card: 'summary_large_image'} %>
<% end %>
```
私の場合は、@replied（質問への返信） が存在するときだけこのOGP画像にしたかったので`if`文をつけ、Twitter card の設定もデフォルトより大きめのものに変えています。

ローカル環境でエラーが出なければ、デプロイしてみて[Twitter cardを確認](https://cards-dev.twitter.com/validator)してみましょう。

<img width="999" alt="スクリーンショット 2019-11-13 19.33.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/96ad70d9-3f2d-e37d-fb4a-2f3ffada6929.png">

Cloudinary の「Media Transformations」に表示させたい文字がきているかも確認してみて下さい。

<img width="571" alt="スクリーンショット 2019-11-13 19.30.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/ddfe8a25-aa64-1938-b4e3-6d24b29fdcc8.png">

### 5. Twitter シェアボタンを配置する

```ruby:app/views/posts/show.html.erb
<% if @replied %>
  <%= link_to "https://twitter.com/intent/tweet?text=#{@replied.content.truncate(118)}&url=#{request.url}/&hashtags=YuppeingApp&lang=ja", title: 'Twitter', class: "twitter-btn btn" do %>
    <i class="fab fa-twitter"></i> Twitterにシェア <i class="fas fa-external-link-alt"></i>
  <% end %>
<% else %>
  <%= link_to "https://twitter.com/intent/tweet?text=Yuppeing-App Yuppyに質問してみよう！&url=https://yuppeing-app.herokuapp.com/&hashtags=YuppeingApp&lang=ja", title: 'Twitter', class: "twitter-btn btn" do %>
    <i class="fab fa-twitter"></i> Twitterにシェア <i class="fas fa-external-link-alt"></i>
  <% end %>
<% end %>
```

Tweet 文に私の返信が載るようにしてあります。`.truncate(118)`で文字数を丸めています。返信がない場合はトップページにも置いてあるデフォルトのシェアボタンに設定しています。(もっとDRYにできるはずです😂)CSSは各自設定して下さい😉

<img width="371" alt="スクリーンショット 2019-11-13 19.46.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/7353e9fb-cae1-6614-e92a-3f889e338e2c.png">

以上です。是非試してみて下さい！