Heroku上のRailsアプリケーションで、OGP画像を動的に生成するための方法をまとめました。

準備

ImageMagick

以前はherokuに別途buildpackを追加する必要があったようですが、現在は必要なくなったようです。

Imagemagick buildpack for Heroku-18 stack

そのため、herokuの最新stackを使えば特に何もする必要は有りません。

MiniMagick

RubyからImageMagickを使うためのgemです。

CarrierWave

ファイルをアップロードするためのgemです。

日本語フォントファイル

今回は画像にテキストを合成して画像生成するので、フォントファイルを使います。

実装

今回はUserモデルが存在するアプリケーションに対して、UserのOGP画像を生成する処理を追加してみようと思います。

やること

  • gem追加

Gemfileに以下を追加

gem 'carrierwave'
gem 'mini_magick'
gem 'fog-aws' # S3にアップロードするために追加

その後

$ bundle install
  • ogpカラム追加

migrationファイルを追加します。

class AddOgpToUser < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :ogp, :string, default: ""
  end
end
  • ogpカラムをCarrierWaveにマウント

Uploaderを追加します。

rails g uploader UserOgp

UploaderをUser.ogpに紐付けます。

# model/User.rb
mount_uploader :ogp, UserOgpUploader
  • OGP画像生成処理

OGPはベースの画像にUserの名前を合成して画像にする仕様とします。

OGP画像生成処理はRubyのClassとして実装します。 ほとんど↓を参考にしました。

【10分でできる】Railsに画像の動的生成機能をサクッと追加する

require 'mini_magick'

class OgpCreator

  BASE_IMAGE_PATH = '/path/to/ogp'
  GRAVITY = 'center'
  TEXT_POSITION = '0,0'
  FONT = '/path/to/font-file'
  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 'white'
      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

  • OGP画像生成呼び出し

今回はプロフィールを変更したときにOGPを生成したいので、UsersControllerに処理を追加します。

# UsersController

def update

  # 略   

  if current_user.update(user_params)
    # プロフィール更新したらogpを生成
    # 生成した画像をアップロード
    # アップロード先のパスをogpに登録
    ogp_image = OgpCreator.build(current_end_user.name)
    current_end_user.update!(ogp: ogp_image)
  else
    # 略   
  end
end

まとめ

以上の方法で動的に生成することができました。

minimagickをさらに調べれば画像操作で色々なことができそうです。

今回のサンプル実装ではとりあえず画像生成するところまでをゴールとしましたが、改善はできそうです。

  • OgpCreatorもConcernにすると良いかもしれません
  • OGP生成処理Workerに任せたほうがパフォーマンスの観点から良いかもしれません

以上です。