1. はじめに
Ruby on Rails 初心者で勉強しながら個人開発中
ActiveStorageで画像アップロード機能を実装したら、環境開発で画像が表示されず、500 エラーが発生しました。
開発環境
・Ruby 3.3.6
・Rails 8.0.2.1
・PostgreSQL
・Docker(開発環境)
・デプロイ: Render / Neon
2. 発生したエラー
ブラウザの「検証」→「コンソール」画面に以下のエラーが表示されてました。
Failed to load resource: the server responded with a status of 500 (Internal Server Error)
さらにサーバーログを確認すると、
NoMethodError (undefined method `source' for module ImageProcessing)
エラーから、ActiveStorage内部でImageProcessing 関連の処理がうまく動いていないことが分かりました。
この記事では、原因の特定から解決までの流れをまとめています。
同じようにActiveStorageで500エラーにハマった人の参考になれば嬉しいです。
3. エラー発生時の状況
ActiveStorageのRailsガイドを参考にしながら、画像アップロード機能を実装。
以下の設定を順に行いました。
1. Gem の追加
gem "image_processing", ">= 1.2"
2. ActiveStorage のセットアップ
docker compose exec web rails active_storage:install
docker compose exec web rails db:migrate
3. config/storage.yml の設定
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
local:
service: Disk
root: <%= Rails.root.join("storage") %>
cloudinary:
service: Cloudinary
cloud_name: <%= ENV["CLOUDINARY_CLOUD_NAME"] %>
api_key: <%= ENV["CLOUDINARY_API_KEY"] %>
api_secret: <%= ENV["CLOUDINARY_API_SECRET"] %>
4. 環境ごとの設定
# config/environments/development.rb
config.active_storage.service = :local
# config/environments/production.rb
config.active_storage.service = :cloudinary
# config/environments/test.rb
config.active_storage.service = :test
5. モデルの設定(一部抜粋)
class Spot < ApplicationRecord
has_many_attached :images do |attachable|
# 一覧画面用
attachable.variant :thumb, resize_to_limit: [200, 200]
# 詳細画面用_スマホ想定なので600で設定
attachable.variant :detail, resize_to_limit: [600,600]
end
end
6. コントローラーのストロングパラメータ(一部抜粋)
private
def spot_params
params.require(:spot).permit(
:name, :address, :tel, :opening_hours, :other_facility_comment,
:latitude, :longitude, :status,
# 子ども向け設備のパラメータ
:child_chair, :tatami_seat, :child_tableware, :bring_baby_food,
:stroller_ok, :child_menu, :parking, :other_facility,
# 複数ファイル 単一なら:image
images: []
)
end
7. ビューでの画像フォーム
div.flex.justify-center.mt-4
-if @spot.images.attached?
- @spot.images.each do |image|
= image_tag image.variant(:thumb), class: "w-32 h-32 object-cover"
※注意
エラーが出た設定を振り返りながら記載した為、記載漏れがあるかもしれません
実際に画像を投稿してみると、画像されず 500 エラーが発生しました。
次の章で原因を特定していきます。
4. 原因と解決までの手順
1.サーバーログエラーの確認
NoMethodError (undefined method `source' for module ImageProcessing)
Active Storage が画像を変換しようとしたときに、ImageProcessing の古いAPIを呼び出して失敗していることが分かります。
Raols8とgem image_processing
のバージョン不整合が原因かを確認
docker compose exec web bundle list | grep image_processing
# 実行結果
image_processing (1.14.0)
image_processing (1.14.0)
は、Rails8 との互換性も確認されているため、ここが原因ではなさそうです。
2. Active Storage のバリアント処理設定
Rails 7以降は、バリアン処理にimage_processing
が必要で、どの処理エンジンを使うかは明示的に設定する必要がある。
とのことでしたが、設定もれてました。
下記を追記
config.active_storage.variant_processor = :vips
Rails 8では Vips 推奨のためVips を使う設定に変更
ただ、この設定だけでは、また画像は表示されませんでした
3.コンソールで確認
gem のバージョン確認・バリアント処理の設定を行ったあと、実際に画像が正しく Active Storage に紐付いているかを確認しました。
# Attachment の総数を確認
# モデル(例:Spot)に紐づいた画像の数をチェックしている
ActiveStorage::Attachment.count
# => 3
# Blob の総数を確認
# データベース上に実際に保存されているファイルの情報が何件あるかをチェックしている
ActiveStorage::Blob.count
# => 3
# 最初の Spot を取得して画像が添付されているか確認
spot = Spot.first
puts "Images attached: #{spot.images.attached?}"
puts "Images count: #{spot.images.count}"
# => Images attached: true
# => Images count: 3
結果を見ると、画像はちゃんと Active Storage に紐づいていることが確認できました。
4.Active Storage で画像の URL を取得
次は実際にブラウザで表示できる URL を取得できるかを確認
spot = Spot.first
url_for(spot.images.first)
# => nil
nil になったことで、Rails がどの host で URL を作ればいいかわからない状態だと判明しました。
# 開発環境で URL を生成できるように host を指定
Rails.application.routes.default_url_options[:host] = "localhost:3000"
Rails.application.config.after_initialize do
ActiveStorage::Current.url_options = Rails.application.routes.default_url_options
end
※注意
上記は 開発環境用 の設定例です。
本番環境で Active Storage の URL が取得できない場合も、同様に Rails.application.routes.default_url_options[:host] を適切なホストに設定してください。
ただ、こちらを記載しても画像は表示されませんでした
5.Docker 側の設定確認
Active Storage で vips を指定すると、Ruby 側の gem ruby-vips
だけでなく、システムに Vips 本体(libvips)が入っている必要があります。Docker 環境では libvips-dev をインストールすることで、Rails が Vips を使って画像のバリアント処理を行えるようになります。
とのことだったので、確認
docker compose exec web vips --version
OCI runtime exec failed: exec failed: unable to start container process: exec: "vips": executable file not found in $PATH: unknown
システムに libvips が入ってない
また、Vips を扱うための gem ruby-vips
が Gemfile に入っていなかった
ことが判明。
Gem 追加
gem "ruby-vips", "~> 2.2"
Dockerfile.dev に追加(libvips インストール)
RUN apt-get update -qq && apt-get install -y \
build-essential \
libpq-dev \
nodejs \
yarn \
vim \
libvips-dev
※補足
上記は Docker 環境用 の例です。
Mac や Windows で Homebrew やパッケージマネージャーを使って Vips をインストール済みの場合は、libvips-dev の追加は不要な場合があります。
環境に応じて Vips が使えるか確認してください。
これで Active Storage が Vips 経由でバリアント処理できるようになり画像が表示されました。
5. まとめ
① Rails 8 + Active Storage で画像が表示されない場合は、まずサーバーログでエラーを確認
② image_processing のバージョンが問題ない場合は、バリアント処理の設定を確認
③ コンソールで Attachment や Blob が正しく紐づいているか確認
④ 開発環境では URL を生成するための host 設定が必要
⑤ Vips を使う場合は、Ruby 側の gem ruby-vips とシステム側の libvips-dev が必要(Dockerなら Dockerfile.dev に追加)
この記事で紹介した手順を順に確認すれば、Active Storage の 500 エラーを解消できるかもしれません。
環境や設定によっては他の原因も考えられるので、うまくいかない場合はログや設定を再チェックしてください。
同じように悩んでいる人の参考になれば嬉しいです。