あまブログ

ドキドキ......ドキドキ2択クイ〜〜〜〜〜〜〜ズ!!

【Rails】ActiveStorageで画像アップロード機能を実装する

この記事では、Rails 5.2からの標準機能であるActiveStorageを使って画像アップロード機能を実装するポイントを紹介します。

1. バージョン情報

  • macOS:12.6
  • Ruby:3.1.2
  • Rails:6.1.6
  • image_processing:1.12.2
  • active_storage_validations:0.9.8

2. 実装時のポイント

2-1. Active Storageのセットアップ

以下を実行して、migrationファイルを作成します。

$ rails active_storage:install
  • db/migrate/XXXX_create_active_storage_tables.active_storage.rbが作成される

migrationを実行します。

$ rails db:migrate

2-2. 画像アップロードと表示

各userにアバター画像を添付したい場合は、以下のようにUserモデルを定義します。

class User < ApplicationRecord
  has_one_attached :avatar
end

以下のように書くことでフォームからアバター画像をアップロードできます。

<div class="field">
  <%= f.label :avatar %>
  <%= f.file_field :avatar %>
</div>
  • ストロングパラメータにavatarの追加が必要

以下のように書くことでアバター画像を表示できます。

<%= image_tag user.avatar if user.avatar.attached? %>
  • avatar.attached?で特定のuserがアバター画像を持っているかどうかを調べられます。

2-3. 画像のリサイズ

画像のリサイズのためにimage_processing gemが必要です。

Gemfileimage_processing gemのコメントを解除します。

# Use Active Storage variant
gem 'image_processing', '~> 1.2'

image_processing gemを使うために、macimagemagickvipsをインストールします。

$ brew install imagemagick vips

variantメソッドで、添付ファイルごとに特定のサイズ違いの画像を生成できます。

<%= image_tag user.avatar.variant(resize_to_fit: [50, 50]) %>

2-4. バリアントプロセッサの変更

Active StorageのデフォルトのバリアントプロセッサはMiniMagickですが、Vipsも指定可能です。

Vipsに切り替えるには、config/application.rbに以下の設定を追加します。

config.active_storage.variant_processor = :vips

設定した値はコンソールからも確認できます。

$ rails c
irb(main):001:0> Rails.application.config.active_storage.variant_processor
=> :vips

2-5. N+1問題の解決

Active Storageでは、画像ファイルを親子モデルのアソシエーションとして関係付けるため、N+1問題を引き起こす可能性があります。

このN+1問題を解決するためにwith_attached_属性名スコープを使用します。

以下のように、app/controllers/users_controller.rbwith_attached_avatarとすることでN+1問題を回避することができます。

class UsersController < ApplicationController
  def index
    @users = User.all.with_attached_avatar
  end
  # 省略
end

2-6. バリデーション

アップロード可能なファイルの種類を限定する方法を紹介します。

方法1. active_storage_validationsを使用する

active_storage_validations gemを使用します。

Gemfileに以下を追記して、bundle installを実行します。

gem 'active_storage_validations'

app/models/user.rbに以下を追記します。

class User < ApplicationRecord
  has_one_attached :avatar
  validates :avatar, content_type: ['image/png', 'image/jpeg', 'image/gif']
end

方法2. 独自のバリデーションヘルパーを実装する

app/models/user.rbに以下を追記します。

class User < ApplicationRecord
  has_one_attached :avatar

  validate :image_check

  private

  def image_check
    return unless avatar.attached?
    return if avatar.image?

    errors.add(:avatar, 'のContent Typeが不正です')
  end
end

フォーム側からファイルの種類に制限をかけるためにacceptを使用します。

<%= f.file_field :avatar, accept: 'image/png,image/gif,image/jpeg' %>

【参考】