【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】Webサーバー「Unicorn」の基本情報と実装方法
# はじめに Railsアプリを本番環境で稼働させるには、クライアントからのリクエストを捌くWebサーバーを導入する必要があります。WebサーバーはクライアントからのリクエストをRailsアプリに伝達し、Railsアプリで処理されたレスポンスをク [...]
2021年4月15日 12:17
【Rails】デプロイツール「Capistrano」の基本情報と実装方法
# はじめに アプリを本番環境にアップロードして誰でもアクセスできる状態にすることをデプロイと言います。デプロイで行うべきことは多岐にわたります。Railsアプリの場合で言えば、本番環境にアップロードすることはもちろんですが、Gemのインストール [...]
2021年4月14日 9:56
【Rails】Webpackerの基本情報と実装方法
# はじめに Rails 6からWebpackerが正式採用されました。Rails 5ではオプションで追加することができたWebpackerですが、Rails 6からは普通にアプリを作成するだけでWebpackerがインストールされ、必要な設定も [...]
2021年4月12日 14:36
【Rails】アセットパイプライン(Sprockets)の基本情報と実装方法
# はじめに Ruby on Railsにはアセットパイプラインという機能があります。アセットパイプラインは画像、CSS、JavaScriptといったアセットファイルを連結/圧縮することでRailsアプリを高速化します。また、より高級な言語で書か [...]
2021年4月11日 14:08
【Rails】Turbolinksの基本情報と実装方法
# はじめに Ruby on Railsにはページの遷移を高速化するTurbolinksという機能があります。Turbolinksは優れたJavaScriptライブラリですが、Rails 5からは標準で有効化されているため、Turbolinksを [...]
2021年4月10日 17:59