【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】Railsアップグレードまとめ
# はじめに Ruby on Railsに限らず、何らかのフレームワークを使ってWebシステムを構築している場合、フレームワークのアップグレード作業は避けて通れません。 一般的にフレームワークはバージョン毎にEOL (End of Life [...]
2022年10月1日 14:32
【Rails】ユーザー登録時に行うメールアドレス認証機能の実装方法
# はじめに ユーザー登録/解除やログイン/ログアウトといった認証機能の導入に「devise」というGemを使っている人は多いと思います。「devise」では以下のように記述するだけで、ユーザー登録時に確認メールを送付しメールアドレス認証を行う機 [...]
2022年9月24日 14:24
【Rails】モデルに列挙型(enum)を定義し、使いこなす方法
# はじめに Railsはモデルでカラム名と同名の列挙型(enum)を定義することで、カラムと列挙型の変数を紐付けることができます。カラムと列挙型の変数を紐付けると、カラムに対して様々な便利な使い方ができるようになります。 本記事では、モデ [...]
2022年9月3日 10:29
【Rails】RailsでCORSとPreflight requestの設定を行う方法
# はじめに RailsアプリをAPIサーバーとして構築するには、CORS (Cross-Origin Resource Sharing)と Preflight requestの設定を行う必要があります。APIサーバーは外部からの要求に対して処理 [...]
2022年8月27日 10:44
【Ruby】Bundlerを使ってRubyGemsを作成/公開する方法
# はじめに Bundlerを使ってRubyGemsを作成および公開する方法について説明します。Bundlerを使わずにRubyGemsを作成/公開する方法については以下の記事を参照してください。 <iframe class="hatena [...]
2022年7月12日 23:18
【Ruby】RubyGemsを作成/公開する方法
# はじめに RubyGemsを作成および公開する方法について説明します。Bundlerを使ってRubyGemsを作成する方法については以下の記事を参照してください。 <iframe class="hatenablogcard" style [...]
2022年7月11日 21:52
【Rails】M1チップ搭載MacでRuby on Railsの開発環境構築
# はじめに M1チップ搭載MacにRuby on Railsの開発環境を構築する手順を記載します。 - MacBook Air (M1, 2020) - macOS Monterey 12.3.1 # Homebrew ## [...]
2022年5月5日 11:56
【Rails】Rakeタスクの基本情報と作成・実行方法
# はじめに Railsには標準でRakeというGemが同梱されています。RakeはRubyで実装されたMake(UNIX系のOSで使用できるコマンド)のようなビルド作業を自動化するツールです。Ruby Make、略してRakeというわけですね。 [...]
2022年3月7日 22:12