「ユーザーのアイコン(アバター)を表示したいけれど、画像アップロードの仕組みをゼロから作るのは面倒そう」——そう感じたことはありませんか?Railsには標準で Active Storage というファイルアップロード機能が用意されていて、gemを1つ足すだけでアバター機能を実装できます。この記事では、Active Storage を使って「画像をアップロード → リサイズして表示 → 未設定ならデフォルト画像を出す」までを、Rails 8 を前提に順を追って解説します。
Rails のセットアップからやり直したい方は、macOSにRuby on Railsをインストールもあわせてどうぞ。認証まわりで Devise を使うか標準ジェネレータを使うか迷っている方は、Rails 8の認証ジェネレータとDeviseはどっちを使う?も参考になります。
この記事でやること
先に、この記事で実装するアバター機能の要件を整理しておきます。
- ログインしているユーザーだけが自分のアバターを変更できる
- アバターを設定していない場合は、デフォルト画像(Gravatar)を表示する
- ページによって異なるサイズで表示できるようにする(一覧では小さく、詳細では大きく等)
それぞれのポイントはこうです。要件1は Devise を導入していれば current_user で判定できます。要件2は Active Storage の attached? で「画像を持っているか」を判定し、無ければ Gravatar にフォールバックします。要件3は Active Storage の variant でサイズ違いの画像を生成します。
前提
- Rails 7 または Rails 8 のアプリがある(Active Storage は標準で同梱)
- Devise などでログイン機能が実装済み(
current_userが使える)
この記事では、Devise 導入済みの boilerplate(ボイラープレート)をベースに進めます。手元にサンプルがない方は、boilerplateを作成してGithubのTemplate Repositoryにする方法も参考にしてください。
Active Storageのセットアップ
すでに Active Storage を設定済みの場合はこの章を飛ばして構いません。まだの方は、以下の3ステップでセットアップします。公式の詳細は Active Storage の概要(Railsガイド)を参照してください。
①libvipsをインストールする
画像のリサイズや切り抜きには libvips を使います。Rails 7.0 以降は変換処理のデフォルトが libvips(ruby-vips)になっているため、ImageMagick ではなく vips を入れておくのがおすすめです。Macなら Homebrew でインストールできます。
$ brew install vips②image_processing gemを有効にする
画像の変換には image_processing gem も必要です。rails new で生成した Gemfile にはコメントアウトされた状態で入っているので、コメントを外すか、無ければ追記します。
gem "image_processing", "~> 1.2"Gemfile を変更したら bundle install を実行します。
$ bundle install③Active Storageをインストールする
インストール用のコマンドとマイグレーションを実行します。これで active_storage_blobs などの管理テーブルが作成されます。
$ bin/rails active_storage:install
$ bin/rails db:migrate開発環境ではローカルディスクに保存する設定になっているか、config/environments/development.rb を確認します。無ければ追加してください。本番環境では AWS S3 などのクラウドストレージを使うのが一般的ですが、その設定はRailsガイドのセットアップを参照してください。
config.active_storage.service = :local⚠️ variant処理のセキュリティ注意(2026年7月)
この記事のように variant(画像変換)を使う場合は、Rails のバージョンに注意してください。2026年7月29日、Active Storage の variant 処理に、細工した画像をアップロードすることでサーバー上の任意のファイルを読み取られる/リモートコード実行につながる脆弱性 CVE-2026-66066 が公表されました。デフォルトの libvips 構成が影響を受けます。
修正版は Rails 7.2.3.2 / 8.0.5.1 / 8.1.3.1 以降です。ユーザーがアップロードした画像を variant で変換するアプリでは、必ず修正版へアップデートしておきましょう。
$ bundle update rails
$ bundle list | grep rails # 7.2.3.2 / 8.0.5.1 / 8.1.3.1 以降になっているか確認Userモデルにアバターを持たせる
まず User モデルに has_one_attached を追加します。これで user.avatar という形でアバター画像を1枚ひも付けられるようになります。
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_one_attached :avatar
validates :first_name, :last_name, presence: true
end
フォームで画像をアップロードできるようにする
次に、プロフィール更新画面からアバターをアップロードできるようにします。Devise の登録編集ビューにファイル選択欄(file_field)を追加します。
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :avatar %><br>
<%= f.file_field :avatar, accept: "image/*" %>
</div>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
accept: "image/*" を付けると、ファイル選択のダイアログで画像だけが選ばれやすくなります。ここでは Devise のビューを直接編集していますが、独自のプロフィール編集画面を使っている場合も同じように file_field :avatar を追加すればOKです。Devise のフォームを分割してカスタマイズしたい場合は、Deviseをカスタマイズして、プロフィール更新とパスワード変更を分ける方法も参考になります。
続いて、コントローラーが avatar パラメーターを受け取れるように、ストロングパラメーターに追加します。Devise の場合は configure_permitted_parameters で許可します。
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name])
devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :last_name, :avatar])
end
end
独自コントローラーの場合は、通常の params.require(:user).permit(..., :avatar) のように :avatar を許可すれば同じことができます。ここまでで、フォームから画像を送信してエラーが出ないことを確認しましょう。
アバター画像を表示する
アップロードした画像は image_tag で表示できます。Active Storage のアタッチメントをそのまま渡せます。
<%= image_tag current_user.avatar, size: 24, class: "rounded" %>ここでは Bootstrap のクラス(rounded)を使っていますが、見た目は自由に調整してください。Tailwind CSS でフォームや UI を整えたい場合は、Tailwind CSSでフォームを綺麗に作る方法もあわせてどうぞ。ヘッダーのユーザーメニューに置くと、次のような見た目になります。

ヘッダー部分のコードは、一部省略すると以下のようになります。
<ul class="navbar-nav">
<li class="nav-item"><%= link_to "News", announcements_path, class: "nav-link #{unread_announcements(current_user)}" %></li>
<% if user_signed_in? %>
<li class="nav-item dropdown">
<%= link_to "#", class: "nav-link dropdown-toggle", data: { bs_toggle: "dropdown" }, aria: { expanded: false } do %>
<%= image_tag current_user.avatar, size: 24, class: "rounded" %>
<% end %>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbar-dropdown">
<%= link_to "Settings", edit_user_registration_path, class: "dropdown-item" %>
<%= link_to "Password", account_password_path, class: "dropdown-item" %>
<div class="dropdown-divider"></div>
<%= button_to "Logout", destroy_user_session_path, method: :delete, class: "dropdown-item" %>
</div>
</li>
<% else %>
<li class="nav-item"><%= link_to "Sign Up", new_user_registration_path, class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Login", new_user_session_path, class: "nav-link" %></li>
<% end %>
</ul>デフォルト画像(Gravatar)を表示する
アバターを設定していないユーザーには、デフォルト画像を出したいところです。画像を持っているかは attached? で判定できます。未設定なら Gravatar の画像にフォールバックさせましょう。
ただし、毎回ビューで if 文を書くと保守性が下がります。そこでヘルパーにまとめて使い回せるようにします。ここでは AvatarHelper を作成します。
module AvatarHelper
def avatar_url_for(user)
if user.avatar.attached?
user.avatar
else
hash = Digest::SHA256.hexdigest(user.email.strip.downcase)
"https://gravatar.com/avatar/#{hash}"
end
end
end
あとは、ビューで avatar_url_for を呼び出すように変更します。
<%= image_tag avatar_url_for(current_user), size: 24, class: "rounded" %>これで、アバターが未設定のときは Gravatar の画像が表示されます。

【2026年時点の注意】Gravatarのハッシュは MD5 → SHA-256 に変わりました。以前は Digest::MD5 でメールアドレスをハッシュ化するのが定番でしたが、Gravatar は2024年に SHA-256 対応を開始し、2025年にはアバターURLのハッシュを SHA-256 へ切り替えました。MD5 はメールアドレスを逆算されやすくプライバシー面でも弱いため、これから実装するなら Digest::SHA256 を使ってください。古い記事の Digest::MD5.hexdigest(...) をそのままコピペすると、Gravatar 画像が正しく表示されない場合があります。ハッシュ化の前に strip.downcase で前後の空白を除去して小文字化するのも忘れずに。
異なるサイズで表示できるようにする(variant)
ここまでで基本機能は満たしていますが、ユーザーが大きすぎる画像や縦横比の偏った画像をアップロードすることを考えると、表示前にリサイズ・切り抜きをしておくと安心です。Active Storage の variant を使うと、元画像を加工したバリエーションを生成できます。ヘルパーを次のように拡張します。
module AvatarHelper
def avatar_url_for(user, size: 48, default: "mp")
if user.avatar.attached?
user.avatar.variant(resize_to_fill: [size, size])
else
hash = Digest::SHA256.hexdigest(user.email.strip.downcase)
"https://gravatar.com/avatar/#{hash}?size=#{size}&default=#{default}"
end
end
end
変更点を解説します。まず、表示サイズをキーワード引数 size: で受け取れるようにしました。呼び出し側で avatar_url_for(user, size: 40) のように指定できます。
user.avatar.variant(resize_to_fill: [size, size]) が画像加工の本体です。resize_to_fill は、指定したサイズに収まるよう中央を基準に切り抜く(余白を作らない)変換なので、アバターのような正方形表示にぴったりです。Gravatar 側にも size(画像サイズ)と default(デフォルト画像の種類。mp は人型のシルエット)を渡して、サイズ感をそろえています。

いろいろなページで使い回す
アバターは、ヘッダーだけでなくユーザー一覧やコメント欄など、さまざまな場所で表示します。ヘルパーにまとめておけば、どこでも avatar_url_for を呼ぶだけで済みます。例えば、次のようなユーザー一覧のUIも簡単に作れます。

参考までに、上のUIのコードは以下のようになります。avatar_url_for 以外の部分は適宜調整してください。
<% @users.each do |user| %>
<div class="d-flex">
<%= image_tag avatar_url_for(user, size: 40), class: "rounded flex-shrink-0 me-2" %>
<p>
<strong class="d-block text-secondary">@<%= user.first_name + user.last_name %></strong>
<%= user.email %>
</p>
</div>
<% end %>まとめ
Active Storage を使って、アバターのアップロード・表示・リサイズ・デフォルト画像までを実装しました。ポイントを振り返ると、次のとおりです。
- アップロードは
has_one_attached :avatar+ ストロングパラメーターで受け取る - 未設定時のフォールバックは
attached?+ Gravatar(ハッシュは SHA-256) - サイズ違いは
variant(resize_to_fill: ...)でリサイズ・切り抜き - variant を使うなら CVE-2026-66066 対策として Rails を修正版へ更新する
アバター機能があるだけで、アプリはぐっと「それっぽく」なります。Active Storage の基本を押さえておくと、投稿画像やサムネイルなど他の機能にも応用が利きます。Rails の実装パターンをもっと知りたい方は、rails ブログ機能の実装方法7選もあわせてどうぞ。
参考までに、今回のコミットログはこちらです。
スポンサーリンク

コメント
Comments are closed.