【Rails】Active Storageの基本情報と実装方法

はじめに

Rails 5.1までは、画像などをアップロードするにはCarrierWaveなどのGemを使う必要がありました。Rails 5.2からActiveStorageという機能が追加され、別途Gemをインストールしなくても組み込みの機能だけで画像などをアップロードできるようになりました。

本記事では、ActiveStorageの使い方についてまとめています。

ActiveStorageの使い方

ActiveStorageを使うと、容易に画像ファイルなどをローカルストレージや代表的なクラウドストレージ(Amazon S3、Google Cloud Storage、Microsoft Azure Storageなど)にアップロードすることができます。また、開発環境はローカルストレージ、本番環境はクラウドストレージというように、環境毎にアップロード先を切り分けることもできます。

ActiveStorageの追加

ActiveStorageはRails組み込みの機能ですが、Railsアプリ作成直後の状態では使うことができません。まずはActiveStorageをRailsアプリに追加する必要があります。

$ rails active_storage:install

上記のコマンドを実行すると、active_storage_blobsおよびactive_storage_attachmentsというテーブルを作成するためのマイグレーションファイルが作成されます。ActiveStorageでアップロードしたファイルの情報などが格納されるテーブルです。

$ rails db:migrate

テストサーバーを起動している場合は再起動してください。これでActiveStorageを使うことができるようになりました。

ActiveStorageの実装

アップロードファイルを追加したいモデルとActiveStorageを紐付けます。モデルに以下を追記します。

# 1ファイルの場合
has_one_attached :image

# 複数ファイルの場合
has_many_attached :images

コントローラーのストロングパラメーターに属性を追加します。ビューから渡されたファイルは、通常のカラムのようにsavecreateを実行することで自動でアップロードされます。

class ArticlesController < ApplicationController
  def create
    article = Article.create!(article_params)
    redirect_to article_path(article.id)
  end

  private
    def article_params
      params.require(:article).permit(:title, :content, :image)
    end
end

フォームにファイル選択フィールドを追加します。

<%= form.file_field :image %>

詳細ページにイメージタグを追加します。

<%= image_tag @article.image %>

これでActiveStorageでファイルがアップロードできるようになり、アップロードしたファイルを表示できるようになりました。

ストレージの種類

ActiveStorageはファイルの保存先ストレージをいくつかの中から選択することができます。各ストレージの設定(アクセストークンやバケットなど)はconfig/storage.ymlに記述します。

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

config/storage.ymlに記述したストレージの中から実際にどれを使うかは、環境毎の設定ファイル(config/environments/ディレクトリ配下)に記述します。通常は、開発環境はローカルストレージ、本番環境はクラウドストレージにします。

# ローカルストレージを使用
config.active_storage.service = :local

Amazon S3の設定

Amazon S3の設定は以下の通りです。なお、AWSの設定については記述していません。

amazon:
  service: S3
  access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
  secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
  region: us-east-1
  bucket: your_own_bucket

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

gem "aws-sdk-s3", require: false

Google Cloud Storageの設定

Google Cloud Storageの設定は以下の通りです。なお、Google Cloud Platformの設定については記述していません。

google:
  service: GCS
  project: your_project
  credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
  bucket: your_own_bucket

キーファイルではなく各パラメーターを記述することもできます。

google:
  service: GCS
  credentials:
    type: "service_account"
    project_id: your_project_id
    private_key_id: <%= Rails.application.credentials.dig(:gcs, :private_key_id) %>
    private_key: <%= Rails.application.credentials.dig(:gcs, :private_key).dump %>
    client_email: your_client_email
    client_id: your_client_id
    auth_uri: "https://accounts.google.com/o/oauth2/auth"
    token_uri: "https://accounts.google.com/o/oauth2/token"
    auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs"
    client_x509_cert_url: your_client_x509_cert_url
  project: your_project
  bucket: your_own_bucket

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

gem "google-cloud-storage", "~> 1.8", require: false

Microsoft Azure Storage

Microsoft Azure Storageの設定は以下の通りです。なお、Microsoft Azureの設定については記述していません。

microsoft:
  service: AzureStorage
  storage_account_name: your_account_name
  storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
  container: your_container_name

Gemfielに以下を追記してbundle installを行います。

gem "azure-storage", require: false

ActiveStorageのバリデーション

ActiveStorageで追加した属性に特化したバリデーションは現在のところ実装されていません。バリデーションは自分で定義することもできるので、ActiveStorageを追加した場合は実装しておきましょう。

自分で定義したバリデーションを呼び出すにはvalidateを使用します。通常のバリデーションvalidatesとは異なるので注意してください。

ファイル種別

選択されたファイルの形式が画像かをチェックするには、以下のように実装します。

validate :file_type

private
  def file_type
    images.each do |image|
      if !image.blob.content_type.in?(%('image/jpeg image/png'))
        errors.add(:images, 'は JPEG 形式または PNG 形式のみ選択してください')
      end
    end
  end

ファイルサイズ

選択されたファイルのサイズをチェックするには、以下のように実装します。

validate :file_size

private
  def file_size
    images.each do |image|
      if image.blob.byte_size > 5.megabytes
        errors.add(:images, 'は 5MB 以下のファイルを選択してください')
      end
    end
  end

ファイルの最大数

選択されたファイルの最大数をチェックするには、以下のように実装します。

validate :file_length

private
  def file_length
    if images.length > 5
      errors.add(:images, 'は 5 ファイルまでにしてください')
    end
  end

画像の変換

アップロードした画像をビューで表示するときに変換することができます。例えば、サムネイル用に100x100程度の小さな画像が必要なとき、自分でリサイズして元の画像とは別にアップロードするというのは面倒です。ActiveStorageのバリアントという機能を使えば、アップロードした画像を基にして簡単にサムネイル用の画像が作成できます。

バリアントを使うにはImageProcessingというGemが必要です。Gemfileに以下を追記してbundle installを行います。テストサーバーを起動している場合は再起動してください。

gem 'image_processing'

ImageProcessingは内部の画像プロセッサとしてMiniMagickというGemを使っています。また、MiniMagickImageMagickというソフトウェアのGem版なので、ImageMagickがインストールされていないと動きません。ややこしいですが、まとめると以下のようになります。

ImageMagick -> MiniMagick -> ImageProcessing

そんなわけで、ImageProcessingを使うためにImageMagickをインストールします。この手順は本番環境でも行う必要があります。

# Macの場合
$ brew install imagemagick

# Ubuntuの場合
$ sudo apt-get install imagemagick

# バージョン確認
$ convert --version

これでバリアントが使えるようになったので、ビューを以下のように変更します。バリアントは画像を表示するときにリサイズするので、好きな場所で好きなサイズの画像を表示できるということです。ただし、リサイズするには多少時間がかかるので使用の際はご注意ください。

<%= image_tag article.image.variant(resize: "100x100") %>

ImgaeMagickで使えるオプションはすべて使えます。

<%= image_tag @user.image.variant(gravity: "Center", resize: "100x100!", crop: "100x100+0+0").processed %>
オプション 説明
gravity 画像変換の始点。convert -list gravityで指定値一覧を表示(デフォルトはNone)。
resize 画像のサイズ。詳しくは Image Geometry - ImageMagick 参照。
crop 始点からの切り抜きサイズ。
precessed 既に変換済みであれば変換しない(キャッシュを表示)。

まとめ

Railsアプリのデプロイ先としてHerokuがよく使われますが、Herokuはデプロイ後にアップロードされたファイルを一定時間後に削除するようになっています。Herokuに限らず、アップロードファイルの保管先はクラウドストレージに委任するのが普通です。

本記事を参考にして、ActiveStorageの使い方を覚えていただければと思います。

関連記事

【Rails】Paranoiaを使用した論理削除(ソフトデリート)
# はじめに Paranoiaは、Railsアプリケーションで論理削除(ソフトデリート)を実現するためのGemです。 論理削除は、データベースのレコードを物理的に削除するのではなく、削除フラグを設定することで「削除済み」とみなす方法です。こ [...]
2024年7月20日 21:33
【Rails】activerecord-multi-tenantを使用したマルチテナントアプリケーションの作成
# はじめに マルチテナントアプリケーションでは、複数の顧客(テナント)が同じアプリケーションを利用するため、データの分離が必要です。 activerecord-multi-tenantは、このようなマルチテナント環境をサポートするための便 [...]
2024年7月18日 16:50
【Rails】RubyとRailsにおけるattr_reader, attr_writer, attr_accessorの概念と使用方法
# はじめに RubyとRailsの開発において、`attr_reader`,`attr_writer`,`attr_accessor`は非常に便利なメソッドです。これらは、クラス内でインスタンス変数に対するゲッターおよびセッターメソッドを簡単に [...]
2024年7月17日 18:11
【Rails】RubyとRailsにおけるyieldの概念と使用方法
# はじめに RubyとRailsにおける`yield`は、メソッドやテンプレートの中で動的にコードブロックを実行する能力を提供し、これによってコードの再利用性と拡張性が大幅に向上します。本記事では、RubyとRailsにおける`yield`の概 [...]
2024年7月17日 13:15
【Rails】AASMを使用してオブジェクトの状態遷移を効率的に管理
# はじめに Railsアプリケーションにおいて、オブジェクトの状態管理は重要な課題の一つです。AASM (Acts As State Machine) gemは、複雑な状態遷移を効率的に管理します。本記事では、AASMの基本的な使い方を解説して [...]
2024年7月16日 18:00
【Rails】RSpec + Swagger + rswagでアプリケーションのAPIをテストおよびドキュメント化する方法
# はじめに Railsアプリケーションの開発において、APIのテストとドキュメント化は重要な要素です。 RSpecはテストフレームワークとして広く利用されており、SwaggerはAPIの設計とドキュメント化を支援します。これらを統合するr [...]
2024年7月16日 14:27
【Rails】mailcatcherを使用して開発環境でメール送信をテストする方法
# はじめに mailcatcherは、開発環境でのメール送信をキャプチャするためのツールです。ローカルで送信されたメールをブラウザ上で簡単に確認できるようにします。mailcatcherをRailsアプリケーションで使用する方法について説明しま [...]
2024年7月15日 16:37
【Rails】impressionistを使用してページビューやクリック数を追跡する方法
# はじめに impressionist Gemを使用してRailsアプリケーションでページビューやクリック数を追跡する方法について説明します。 # 実装方法 ## impressionist Gemのインストール まず、impre [...]
2024年7月15日 14:18