2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】MiniMagickでの動的OGP画像生成エラーとGitHub Actions(CI)突破の完全トラブルシューティング

2
Posted at

はじめに

自作サービス(絶望えらぁ短歌)で投稿内容に応じた動的OGP画像を生成する機能を実装した際、いくつかのエラーやハマりポイントに遭遇しました。

この記事では、発生したエラーの原因分析から解決までのプロセスを備忘録としてまとめます。


検証環境

📝 のちの自分用メモ:バージョンが変わると再現しない/しなくなるエラーもあるため、当時の環境を残しておく。

項目 バージョン
Ruby 3.3.0
Rails 8.1.3.1
ImageMagick 7.1.1-43
mini_magick (gem) 5.3.3
デプロイ先 Render

1. RecordNotFound(IDの不整合)

発生した現象・初期の仮説

OGP画像の生成リクエスト時にデフォルト画像にフォールバックしてしまい、ログに以下が出力された。

OGP Generation Failure: ActiveRecord::RecordNotFound - Couldn't find Post with 'id'="1"
  • 初期仮説1: OGP生成処理(コントローラのアクションやルーティング)自体にバグがあり、正しいIDを渡せていないのではないか?
  • 初期仮説2: ID体系ではなく、この時点ではまだ疑っていなかったMiniMagick/ImageMagick側の処理でエラーが起きているのではないか?

検証と真因

  • 検証: Railsコンソールで Post.pluck(:id) を実行し、実際に存在するIDを確認したところ、そもそも id: 1 のレコード自体が存在しないことが判明。ロジックのバグではなくデータ側の問題だと特定した。
  • 真因: 開発用データベースでデータの削除・追加を繰り返していたことで id: 1 のレコードが存在しなくなっていたにもかかわらず、リクエスト側は id: 1 決め打ちのままだったため。

🔍 見分け方:Couldn't find XXX with 'id'= が出たら、まずロジックのバグより先にDBの中身(seedやテストデータの削除漏れ)を疑う。

対策

Railsコンソールで実際のIDを確認し、存在するデータに対してリクエストを行うように修正。

# Railsコンソールで存在するIDを確認
Post.pluck(:id)
# => [2, 3, 4, 5, ...]

2. MiniMagickのエラー(Errno::ENOENT / no encode delegate for this image format 'CANVAS'

発生した現象・初期の仮説

MiniMagick::Image.open("xc:#050202") を実行した際、Errno::ENOENTno encode delegate for this image format 'CANVAS' が発生した。

  • 初期仮説1: ローカルとDocker環境でImageMagickのバージョンやDelegate(PNG等のエンコーダ)のインストール状態が異なるのではないか?
  • 初期仮説2: xc: 記法のフォーマット指定の問題ではなく、コンテナ内のImageMagickが壊れているのではないか?

検証と真因

  • 検証: コンテナ内で convert --version を確認したところ、Delegatesに pngfreetype が正しく組み込まれていることを確認(ImageMagick 7.1.1-43)。環境の問題ではなくコード側の記述問題だと特定した。
  • 真因:
    1. MiniMagick::Image.open は既存ファイルを開くメソッドのため、xc: をファイルパスとして処理しようとして Errno::ENOENT になる。
    2. Tool::Convert に切り替えた際も、一時ファイル(f.path)に拡張子(.png)が付与されないため、ImageMagickが「フォーマット不明(CANVAS)」と判定して出力エラーになる。

🔍 見分け方:エラーメッセージだけ見ると環境依存を疑いたくなるが、convert --version でDelegateの有無を確認できれば、環境要因かコード要因かを素早く切り分けられる。

対策

入力側の xc:(単色キャンバス生成)と、出力先パスへの png:(PNGエンコードの明示)を両方指定することで完全解決した。

# ⭕ 正しいコマンド構築
MiniMagick::Tool::Convert.new do |config|
  config.size "1200x630"
  config << "xc:#{OGP_BG_COLOR}"
  config << "png:#{f.path}" # 出力フォーマットを明示
end

最終的な実装(修正後コード全体)は以下の通り。

def ogp
  post = Post.find(params[:id])

  tanka_text  = (post.tanka.presence || "デフォルトテキスト").tr("\n", " ")
  author_text = "詠み手:#{post.author_name.presence || '名無し法師'}"

  # 単色背景のキャンバス画像を生成(xc: と png: を明示)
  image = MiniMagick::Image.create do |f|
    MiniMagick::Tool::Convert.new do |config|
      config.size "1200x630"
      config << "xc:#{OGP_BG_COLOR}"
      config << "png:#{f.path}" # png形式を明示
    end
  end

  # テキストの描画
  image.combine_options do |c|
    c.fill OGP_TEXT_COLOR
    c.pointsize "38"
    c.gravity "center"
    c.draw "text 0,-30 #{tanka_text.inspect}"
    c.fill OGP_AUTHOR_COLOR
    c.pointsize "24"
    c.draw "text 0,150 #{author_text.inspect}"
  end

  send_data image.to_blob, type: "image/png", disposition: "inline"
rescue StandardError => e
  Rails.logger.error("OGP Generation Failure: #{e.class} - #{e.message}")
  send_file Rails.root.join("app/assets/images/default_ogp.jpg"), type: "image/jpeg", disposition: "inline"
end

3. X(旧Twitter)でOGPカードが表示されない問題

発生した現象・初期の仮説

Render(本番環境)へデプロイ後、Xでツイートしても画像が表示されずリンクだけになる。

  • 初期仮説1: RenderのLinuxサーバー上に ImageMagick やフォントが入っておらず、本番でのみ MiniMagick::Error が発生してデフォルト画像(またはエラー)になっているのではないか?
  • 初期仮説2: OGP画像のメタタグ(og:image)のURLが http:// になっており、Xのクローラーに拒否されているのではないか?

検証と真因

  • 検証:
    1. 本番の画像URL(https://despair-tanka.onrender.com/posts/xx/ogp)へ直接アクセス → 正常に綺麗な画像が表示される(サーバー・コードは正常)。
    2. OGP確認ツール(Card Validator等)でURLを検証 → 正常に画像カードが生成される。
  • 真因: アプリ開発途中(画像が正しく生成できていなかった頃)にXのクローラーがそのURLへアクセスした際の「失敗データ(または画像なし状態)」が、X側に強力にキャッシュされていた。

🔍 見分け方:実装・レスポンス自体(curlやブラウザでの直接アクセス)は正常なのにX上だけ反映されない場合は、まずクローラー側のキャッシュを疑う。

対策

X Card Validator 等の確認ツールで対象URLを一度読み込ませることで、X側のクローラーキャッシュを強制的・即時に最新の動的OGP画像へ更新させた。


4. CI(GitHub Actions)のハマりポイント

リリース直前、CIが赤(Failure)になったため以下の対応を実施。

① Lint(RuboCop)エラー

  • 現象: 末尾の不要な空白(Layout/TrailingWhitespace)でCIが赤に。
  • 対策: bundle exec rubocop -a で自動修正。

② Gitコミット時の -m 忘れ

  • 現象: git commit "メッセージ..." を実行した際、pathspec ... did not match any file(s) エラーが発生。
  • 原因: -m オプションを付け忘れたため、Gitがメッセージを「削除・変更対象のファイル名(pathspec)」だと誤認識した。
  • 対策: git commit -m "メッセージ" で正しく指定。

③ BrakemanのGem更新で frozen mode に弾かれる

  • 現象: bundle update brakeman を実行しても version stayed the same となり更新されず、Dockerコンテナ内では the lockfile can't be updated because frozen mode is set が発生。
  • 原因:
    1. Gemfileにバージョン指定(>= 8.0.6)がなかったためBundlerが更新をスキップしていた。
    2. Docker環境のBundlerで frozen modeGemfile.lock の変更禁止設定)が有効になっていた。
  • 対策:
    1. Gemfileに gem "brakeman", ">= 8.0.6", require: false を明記。
    2. docker compose exec web bundle config set frozen false で一時的にロックを解除してから bundle update を実行。

test/system 不在による LoadError

  • 現象: bin/rails test:system 実行時に cannot load such file -- .../test/system (LoadError) が発生。
  • 原因: bin/ci スクリプト内ではシステムテストがコメントアウトされていたが、GitHub Actions(ci.yml)側ではシステムテストが起動するように記述されており、かつリポジトリ内に test/system ディレクトリ自体が存在しなかった。
  • 対策: mkdir -p test/system && touch test/system/.keep で空ディレクトリと .keep ファイルを作成・コミットして解消。

エラー早見表(サマリー)

# エラーメッセージ(抜粋) 原因 解決策
1 Couldn't find Post with 'id'=... 存在しないIDへのリクエスト 実在するIDでリクエスト/DBの状態を確認
2 Errno::ENOENT ... xc:#050202 MiniMagick::Image.open がカラー指定をファイルパスと誤認識 MiniMagick::Tool::Convert でコマンド組み立て
2 no encode delegate for this image format 'CANVAS' 一時ファイルに出力フォーマット未指定 xc:png: を明示指定
3 Xでカード非表示(テキストリンクのみ) Xクローラーの古いキャッシュ Card Validatorで再Fetch
4 pathspec ... did not match any file(s) git commit-m を付け忘れ git commit -m "..." で正しく指定
4 the lockfile can't be updated because frozen mode is set Gemfileのバージョン未指定+Bundlerのfrozen mode バージョン指定を明記し bundle config set frozen false
4 cannot load such file -- .../test/system (LoadError) test/system ディレクトリの不在 mkdir -p test/system && touch test/system/.keep

おわりに

ImageMagickやMiniMagickのコマンド組み立ては独自のハマりどころが多く、ログを正確に読み解く重要性を改めて実感しました。
同じようなエラーで詰まっている方の参考になれば幸いです!

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?