はじめに
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
コントローラーのストロングパラメーターに属性を追加します。ビューから渡されたファイルは、通常のカラムのようにsave
やcreate
を実行することで自動でアップロードされます。
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を使っています。また、MiniMagick
はImageMagick
というソフトウェアの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の使い方を覚えていただければと思います。