Mima Design MemottoWEB DESIGNER · mima

Railsで画像アップロード機能を追加する手順

Railsアプリケーションに画像アップロードを組み込むなら、まず標準機能のActive Storageを利用する方法が扱いやすい選択肢です。保存先や画像との関連付けをRailsの規約に沿って管理できるため、プロフィール画像や記事のサムネイルを比較的少ないコードで実装できます。

画面設計と実装を行き来しながら検証した記録は、Mimaの制作記録にも通じるテーマです。今回はRails 7以降を想定し、環境準備からフォーム、バリデーション、表示、テストまでの流れを整理します。

Active Storageを準備する

Active Storageを導入するには、プロジェクトのルートで次のコマンドを実行します。

bin/rails active_storage:install
bin/rails db:migrate

この操作によって、アップロードされたファイルを管理するactive_storage_blobsと、モデルとの関連を記録するactive_storage_attachmentsが作成されます。開発環境では初期設定のローカル保存が利用されます。

本番環境でAmazon S3などを使う場合は、config/storage.ymlに接続情報を設定し、環境ごとのconfig/environments/production.rbで保存先を指定します。アクセスキーはソースコードに直接書かず、環境変数で管理してください。

モデルに画像を関連付ける

たとえばUserモデルにプロフィール画像を1枚だけ紐付ける場合は、次のように記述します。

class User < ApplicationRecord
  has_one_attached :avatar
end

記事に複数の画像を登録したい場合は、has_many_attached :imagesを使います。Active Storageはファイル本体とモデルの関連を分離して管理するため、ユーザー情報を削除する処理と画像の扱いも確認しておくことが大切です。

画像の変換を行う場合は、ImageMagickまたはlibvipsを利用します。Railsの設定や環境に応じてimage_processingをGemfileへ追加し、必要なライブラリを開発環境と本番環境の両方に用意します。

フォームとコントローラーを実装する

フォームではmultipart/form-dataを扱うため、form_withにmultipart: trueを指定します。

<%= form_with model: @user, multipart: true do |form| %>
  <%= form.file_field :avatar, accept: "image/png,image/jpeg,image/webp" %>
  <%= form.submit "保存" %>
<% end %>

コントローラーではStrong Parametersに画像属性を追加します。これを忘れると、選択したファイルが送信されてもモデルへ設定されません。

def user_params
  params.require(:user).permit(:name, :avatar)
end

更新処理では@user.update(user_params)を実行し、失敗時には入力画面を再表示します。保存前にプレビューを表示したい場合は、JavaScriptのURL.createObjectURLを使うと、サーバーへ送信せず選択画像を確認できます。

バリデーションと安全性を整える

アップロード機能では、拡張子だけでなくファイルのMIMEタイプとサイズを検証します。Railsのバージョンによって利用できるバリデーションの記法が異なるため、プロジェクトの公式ドキュメントを確認しながら実装します。

class User < ApplicationRecord
  has_one_attached :avatar

  validates :avatar,
    content_type: ["image/png", "image/jpeg", "image/webp"],
    size: { less_than: 5.megabytes }
end

不正なファイルを画像として扱わないこと、公開範囲を意識してURLを設計することも重要です。個人情報を含む画像は、誰でも取得できる公開URLではなく、認証済みユーザーだけが閲覧できる配信方法を検討してください。

画像を表示して加工する

保存済みの画像はimage_tagとurl_forを組み合わせて表示できます。

<% if @user.avatar.attached? %>
  <%= image_tag @user.avatar, alt: "#{@user.name}のプロフィール画像" %>
<% end %>

サムネイルを生成する場合は、variantで幅や高さを指定します。処理には時間がかかる場合があるため、一覧画面で大量の画像を表示するときは、適切なサイズの画像をあらかじめ生成する設計が効果的です。

フロントエンドとの連携や画像処理の考え方を広げる資料として、Next.jsとDenoの画像処理のような別構成の事例も参考になります。Rails単体で完結させるか、専用の配信基盤を組み合わせるかを要件で判断しましょう。

運用前に確認する項目

開発環境で動作しても、本番環境では保存先、権限、画像変換用ライブラリ、CDN設定などで問題が起こることがあります。デプロイ後に実際の画像をアップロードし、表示、削除、再アップロードまで確認してください。

実装前には次の項目を整理しておくと、後からの修正を減らせます。

  • 許可する形式と最大ファイルサイズを決める
  • 公開画像と非公開画像の扱いを分ける
  • 保存先とバックアップ方針を設定する
  • 大きな画像のリサイズ方法を決める
  • 失敗時のエラーメッセージを画面に表示する

RSpecやMinitestでは、正常な画像、サイズ超過、未対応形式、画像未選択のケースを用意します。イベントや技術交流で得た実装の視点は、カンファレンス参加記のような学習ログに残しておくと、後で設計判断を振り返る際にも役立ちます。

まずはローカル保存で最小構成を完成させ、モデルへの関連付け、フォーム送信、表示、削除を順に確認しましょう。その後、バリデーションと認証を追加し、本番用ストレージへ移行すると、原因を切り分けながら安全にRailsの画像アップロード機能を育てられます。