【動的OGP】 Rails7, Dockerを使ってXシェアを実装する
はじめに
こんにちは!! プログラミング初学者のyukimuraです!
今回は私自身の個人開発したアプリで実装したXシェア機能について記述しています
間違いなどありましたら、優しくご指摘いただけましたら幸いです。
個人開発アプリ
GithubURL前提
今回アプリのデプロイはRender.comを使用しました
Render.comでの画像保存はAmazonS3の使用が必要ですが、Xシェアのみの画像使用であれば保存まで必要なかったので、今回は画像保存をせずに都度画像を生成するアプローチでの動的OGPを実装します
今回の実装では、下記記事を大変参考にさせていただきました
環境
- docker
- rails 7.0.8.4
- ruby 3.2.3
- tailwind
OGPとは
OGPとは「Open Graph Protocol」の略で、Webサイト内の記事がFacebookやTwitterなどのSNSで拡散・シェアされた際に、各ページのタイトルやサムネイル画像といった情報を表示させるための機能です。
OGP(Open Graph Protocol)を設定する目的は、URLがソーシャルメディアやメッセージングアプリでシェアされたときに、そのURLに関する情報を豊かに表示することになります。
簡単にいうと、URLを共有したときにただURLが共有されるのではなくて、画像などのその他の情報が装飾されて表示されるということです
例
事前準備
背景画像を用意してください
Canvaなどのアプリで背景画像を作成してください。
大きさは1200 x 627です
画像の大きさは参考記事の下記部分を参考にしました
使用するフォントを決めてダウンロードをしてください
無料でのフォントは多くあります。ご自身の好みのフォントをご用意ください
使用するgemとその役割
今回のメインとなるgemは2つです
1. gem meta-tags
metaタグを設定して、URLがシェアされた時に画像などの情報で装飾をする役割の為に使用します
2. gem mini_magick
metaタグでURLがシェアされた時にユーザーが作成したタイトルと用意した画像を合成する役割のために使用します
実装を開始する
画像の合成を行える様にする
gem mini_magick
を使用するためにImageMagick
を導入する
1. mini_magickを使用するには、ImageMagickが必要です。
簡単にいうと、ImageMagickを各言語で使いやすくしたものの一つがMiniMagickだからです
DockerFileに記述する
DockerFileにimagemagickを記述して導入する
# syntax = docker/dockerfile:1
ARG RUBY_VERSION=3.2.3
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
WORKDIR /rails
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"
FROM base as build
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential curl git libpq-dev libvips node-gyp pkg-config python-is-python3
ARG NODE_VERSION=20.13.1
ARG YARN_VERSION=1.22.22
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
/tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
npm install -g yarn@$YARN_VERSION && \
rm -rf /tmp/node-build-master
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
RUN bundle exec bootsnap precompile app/ lib/
ENV SECRET_KEY_BASE=Rails.application.config.secret_key_base=ENV['SECRET_KEY_BASE']
RUN ./bin/rails assets:precompile
FROM base
### この部分のpostgresql-clientの後ろにimagemagickを追加 ###
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libvips postgresql-client imagemagick && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /rails /rails
RUN useradd rails --create-home --shell /bin/bash && \
chown -R rails:rails db log storage tmp
USER rails:rails
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
EXPOSE 3000
CMD ["./bin/rails", "server", "-b", "0.0.0.0", "-p", "3000"]
その後
-
docker compose build
等を行ってください - また、コンテナ内で下記コマンドを使ってImageMagickが導入されているか確認してください
convert -version
2. gem 'mini_magick'の導入
Gemfileに記述
gem 'mini_magick'
その後
bundle install
3. 画像生成機能を実装する
- ダウンロードしたフォントファイルを、app/assets/fonts配下に配置してください
- app/controllers/concerns以下にogp_creator.rbを作成してください
これは、画像を作成するクラスです
下記のコードを記述して、背景画像ファイルのパス・フォントファイル名をそれぞれ記載してください
class OgpCreator
require 'mini_magick'
BASE_IMAGE_PATH = './app/assets/images/{ 背景画像ファイル名を記載 }'
GRAVITY = 'center'
TEXT_POSITION = '0,0'
FONT = './app/assets/fonts/{ フォントファイル名を記載 }'
FONT_SIZE = 65
INDENTION_COUNT = 16
ROW_LIMIT = 8
def self.build(text)
text = prepare_text(text)
image = MiniMagick::Image.open(BASE_IMAGE_PATH)
image.combine_options do |config|
config.font FONT
config.fill 'red'
config.gravity GRAVITY
config.pointsize FONT_SIZE
config.draw "text #{TEXT_POSITION} '#{text}'"
end
end
private
def self.prepare_text(text)
text.to_s.scan(/.{1,#{INDENTION_COUNT}}/)[0...ROW_LIMIT].join("\n")
end
end
4. OGP用のコントローラーを作成
- viewファイルは必要ないので作成しない
bin/rails g controller images ogp --skip-template-engine
- 下記コードを記述する(アプリではsorceryの認証を実装しているので、
skip_before_action
を設定しています)
class ImagesController < ApplicationController
skip_before_action :require_login, raise: false
def ogp
text = ogp_params[:text]
image = OgpCreator.build(text).tempfile.open.read
send_data image, type: 'image/png', disposition: 'inline'
end
private
def ogp_params
params.permit(:text)
end
end
解説は参考記事のこちらを見てください
5. ルーティングの設定
config.routus.rbにルーティングを設定
get 'images/ogp.png', to: 'images#ogp', as: 'images_ogp'
6. 動作を確認する
URLで/images/ogp.pngにアクセスし、textパラメーターを追加して見てください
下記画像はURLがlocalhost:3000/images/ogp.png?text=おはよう
の場合の画像です
- textパラメーターをhogehogeなど文字に変更して画像が変わったら成功です
Metaタグを実装する
次に、gem 'meta-tags'を導入
1. Gemfileに記述
gem 'meta-tags', require: 'meta_tags'
その後
bundle install
2. meta_tags:installコマンドで設定ファイル追加
コンテナに入って、下記コマンドでconfig/initializers/meta_tags.rbを作成します
rails generate meta_tags:install
作成されたファイルは特に記述を追加せずに大丈夫です
# frozen_string_literal: true
MetaTags.configure do |config|
end
3. application.html.erbにdisplay_meta_tagsメソッドを追加する
<!DOCTYPE html>
<html>
<head>
<title><%= page_title(yield(:title)) %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
<!-- meta_tag -->
<%= display_meta_tags %>
</head>
4. postコントローラーにmetaタグの設定を記述する
今回は普通の投稿機能(postコントローラー)を使って実装しました
Postテーブルにはtitleカラム、bodyカラムなどがあります
ユーザーがcreateアクションによって、作成・保存したtitleカラムの値を表示する用にします
postコントローラーを下記の様に記述します(該当部分以外省略しています)
class PostsController < ApplicationController
## 設定したprepare_meta_tagsをprivateにあってもpostコントローラー以外にも使えるようにする
helper_method :prepare_meta_tags
def show
@post = Post.find(params[:id])
## メタタグを設定する。
prepare_meta_tags(@post)
end
private
def prepare_meta_tags(post)
## このimage_urlにMiniMagickで設定したOGPの生成した合成画像を代入する
image_url = "#{request.base_url}/images/ogp.png?text=#{CGI.escape(post.title)}"
set_meta_tags og: {
site_name: '詐欺師の手帳',
title: post.title,
description: 'ユーザーによる詐欺被害の投稿です',
type: 'website',
url: request.original_url,
image: image_url,
locale: 'ja-JP'
},
twitter: {
card: 'summary_large_image',
site: '@https://x.com/yukimura877',
image: image_url
}
end
end
解説
-
helperファイルでの設定はアプリ全体でのデフォルトの設定を行えるものなので、
今回はshow画面の内容だけがシェアできたらいいので設定をコントローラーで行う。
set_meta_tags
はgem meta-tagsが用意しているメソッドで、ページなどに合わせてメタタグを設定することができる -
image_url = "#{request.base_url}/images/ogp.png?text=#{CGI.escape(post.title)}"
ここで画像を合成しています
(post.title)はshowアクションで取得したユーザーが作成したpostテーブルのtitleカラムにある値を代入しています
自分のアプリでは上記の様に設定しました
set_meta_tags og:
以降の設定は参考記事の下記部分を参照してください
5. show.html.erbで設定する
- show.html.erbファイルにXシェアボタンを導入し、meta-tagを設定します
<div class="text-gray-600">
<% prepare_meta_tags @post %> ## 設定したメタタグをリダイレクトされる前に呼び出す
<% twitter_share_url = "https://twitter.com/share?url= #{CGI.escape(post_url(@post))}" %> ## post_urlにしないと完全なURLにならない
<%= link_to twitter_share_url, target: '_blank', data: { toggle: "tooltip", placement: "bottom" }, title: "Xでシェア" do %>
## Xシェアボタンはfontawesome.comから使用しています
<i class="fa-brands fa-square-x-twitter fa-2xl"></i>
<% end %>
</div>
補足
-
<% twitter_share_url = "https://twitter.com/share?url= #{CGI.escape(post_url(@post))}" %>
ここでは、シェアされるURLを設定します。
今回は、他のユーザーがOGPにアクセスしたときにposts/show/該当のID
のshowページにアクセスして欲しいので、post_url(@post)と設定します - CGI.escapeを使用して、URLの文字をエンコードしています
https://docs.ruby-lang.org/ja/latest/method/CGI/s/escape.html
実装を確認する
本番環境にpushしなくても、下記Chrome拡張機能を使うとローカルでも確認できます
1. cromeに下記の拡張機能を追加してください
2. 追加を完了したら、下記動画の様にサーバーを立ち上げてください。
ローカルホストでのURLを変更して新しいURLを作成してくれます
3. 上記で生成されたURLをコピーした後に、Xのリンクボタンをクリックしてください
4. 先ほどコピーしたURlを貼り付けて、Preview.cardをクリックしてください
ここでのlogで、successとなっていたら設定はできています!!
5. コピーしたURLを実際のツイッター投稿で貼り付けても確認できます
おまけ(静的OGPの設定)
静的OGPの実装も記述します
gem MiniMagick
の導入部分とフォントのダウンロードは必要ありません
1. 静的OGPのみならば最初に下準備と同じように、装飾した画像を作成してください
自分のアプリでは、下記画像にしました
大きさも動的OGPと同じです
2. application_helper.rbにデフォルトのOGPを設定します
# frozen_string_literal: true
module ApplicationHelper
def default_meta_tags
{
site: '詐欺師の手帳',
title: '詐欺師の手帳',
reverse: true,
charset: 'utf-8',
description: '詐欺被害の未然防止を目的としたアプリです',
canonical: request.original_url,
og: {
site_name: '詐欺師の手帳',
title: '詐欺師の手帳',
description: '詐欺被害の未然防止を目的としたアプリです',
type: 'website',
url: request.original_url,
image: image_url('default_share.png'),
local: 'ja-JP'
},
twitter: {
card: 'summary_large_image',
site: '@https://x.com/yukimura877',
image: image_url('default_share.png')
}
}
end
end
3. application.html.erbのdisplay_meta_tagsメソッドに引数を追加する
<!DOCTYPE html>
<html>
<head>
<title><%= page_title(yield(:title)) %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<!-- meta_tag -->
<%= display_meta_tags(default_meta_tags) %>
</head>
4. 上記で実装完了です
終わりに
- Dockerを使用する際に、ImageMagickの導入をHomebrewなどを使ってPCに直接導入する際は一つ注意が必要です
なぜなら、デプロイする際にデプロイサーバー(本番環境)にはImageMagickがインストールされていないからです。MiniMagickはImageMagickがインストールされていないと使用できません
なので、DockerFileに記述してコンテナにインストールしないと本番環境でエラーが発生すると思います - 以上になります。これから実装される方のお力に少しでも慣れたら幸いです
最後までご覧いただきありがとうございました!!!
Discussion