最近ぼちぼちアウトプットしようとせこせこインプットしています。
前回Rails5.2でたからActionCable試すという舐めた記事を書いたので今回はちゃんとActiveStorageを試します!
ActiveStorageとは
ActiveStorageはRails5.2から標準で搭載されるようになったファイルアップローダーです。
AWS S3などのクラウドストレージへのアップロードも設定で手軽に実装できる代物です。
今日はこのActiveStorageを使って簡単な画像も投稿できる機能を作ります。
導入
まずは適当にrails new
でサンプルアプリプロジェクトをつくります。
(DBにpostgresql使いますがなんでもOKです)
$ rails new active_storage_sample -d postgresql
プロジェクトができたらGemfile内のmini_magick
のコメントアウトを外します。
画像処理のために導入するためです。
# Use ActiveStorage variant
gem 'mini_magick', '~> 4.8' # ここのコメントアウト外す
コメントアウトを外したらbundle install
でインストールしておきます。
これで導入に必要なものは整いました。
ActiveStorageをインストールする
ActiveStorageを使うためにはまずインストールのコマンドを実行します。
$ rails active_storage:install
実行するとActiveStorageでアップロードファイルを管理するテーブルのmigrationファイルが生成されるのでrails db:migrate
を実行しておきましょう。
生成されるテーブルは以下の二つになります。
active_storage_blobs
カラム名 | 保存内容 |
---|---|
id | ID |
key | ファイルを一意に識別するkey |
filename | アップロードしたファイルの名前 |
content_type | ファイルの種類 |
metadata | メタデータ(画像なら縦横の大きさなどが格納される) |
byte_size | ファイルサイズ(byte単位) |
checksum | チェックサム |
created_at | 作成日時 |
active_storage_attachments
カラム名 | 保存内容 |
---|---|
id | ID |
name | モデルの属性名(Userモデルのavatarとか) |
record_type | モデル名(Userとか) |
record_id | record_typeのモデルのID |
blob_id | active_storage_blogsのID |
created_at | 作成日時 |
ActiveStorageの設定を確認する
ファイルの格納先はconfig/storage.yml
で設定されています。
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
local:
service: Disk
root: <%= Rails.root.join("storage") %>
例えばlocal
の設定を使えばプロジェクトルートにあるstorageディレクトリ
配下にファイルを格納するという意味になります。
次にconfig/environments/development.rb
をみてみます。
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
という記載があり格納先にconfig/storage.yml
で定義したlocal
の設定を使うよという設定が書いてあります。
これで設定の確認は完了です。
ファイルアップロードする画面を作る
まずは画像アップロードできるようにUserモデルを作ります。
$ rails g model user name:string
ActiveStorageを扱う際は画像アップロード用のカラムを定義する必要はありません。
コマンドを実行したらrails db:migrate
を実行します。
Userモデルができたら、ActiveStorageを使うための記述を追記しておきます。
class User < ApplicationRecord
has_one_attached :avatar # 追記
end
この追記を行うことでUserモデルにavatarという画像を扱う属性が付与されます。
has_oneがあればhas_manyもあります。
has_many_attached
を利用すれば複数画像を扱うこともできます。
詳しくはこちらで
ActionStorageを使うための記載はだいたい終了なので、あとはざっと画面などを作成します。
Rails.application.routes.draw do
root "users#index"
resources :users, only: [:new, :create]
end
class UsersController < ApplicationController
def index
@users = User.all
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
redirect_to root_url, notice: 'Add User'
else
render :new
end
end
private
def user_params
params.fetch(:user, {}).permit(:name, :avatar)
end
end
<h1>Add User</h1>
<%= form_with model: @user, local: true do |form| %>
<div>
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div>
<%= form.label :avatar %>
<%= form.file_field :avatar %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
<h1>Users Index</h1>
<%= link_to 'Add user', new_user_path %>
<ul>
<% @users.each do |user| %>
<li>
<p><%= user.name %></p>
<%= image_tag user.avatar %>
</li>
<% end %>
</ul>
ここまでやると、こんな感じになります。
という感じですごく簡単に画像アップロードが実装できてしまいます!
S3にアップロードできるようにする
S3でバケットを作る
せっかくなのでS3にアップロードできるようにしてみます。
まずはAWS S3で適当な名前のバケットを作成します。
(わかりやすくactive-storage-sampleというバケットを作りました)
作成したらS3を操作できるIAMユーザーを作成してアクセスキーとシークレットキーを取得しておきましょう。
格納先の設定をS3に向くように変更する
config/storage.yml
の以下のコメントアウトを外します。
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: ap-northeast-1
bucket: active-storage-sample
config/environments/development.rb
で先ほどlocal
となっていることを確認した設定をamazon
に変更します。
config.active_storage.service = :amazon # :localを:amazonに変更
またS3へのアップロードを行うためにaws-sdk-s3
を導入します。
Gemfileに以下を追記しましょう。
gem 'aws-sdk-s3'
追記したらbundle install
しておきます。
アプリケーションからS3につなぎこむ
アプリケーションからS3につなぎこむためにIAMユーザーを作成して取得したアクセスキーとシークレットキーを設定しましょう。
Rails5.2からcredentialsという機密情報を暗号化する機能が追加されています。
これを使ってアクセスキーとシークレットキーを設定します。
$ EDITOR=vim rails credentials:edit
これを実行するとエディタ(この記載だとvim)が開いてキーを設定できます。
エディタが開いたら以下のように設定を記載します。
aws:
access_key_id: アクセスキー
secret_access_key: シークレットキー
記載したら保存して閉じます。
するとconfig/credentials.yml.enc
というファイルとconfig/master.key
というファイルができています。
config/credentials.yml.enc
は暗号化されているので内容を見ることはできません。
暗号化のキーにはconfig/master.key
に記載されているキーが使用されています。(環境変数RAILS_MASTER_KEY
が設定されていれば、これを使う)
設定を確認したい場合はrails credentials:show
を実行すれば生のデータを確認することができます。
先ほどconfig/storage.yml
でコメント外したところに
Rails.application.credentials.dig(:aws, :access_key_id)
という記載がありましたが、これはcredentialsのawsのaccess_key_idを取得するという記載になります。
ここまで設定できれば画像を保存した際にローカルではなくS3にファイルが格納されるようになっています。
クラウドストレージへのアップロードも少ない手順で実現できてしまうのはお手軽で素晴らしいですね。
ちなみに
config/master.key
やRAILS_MASTER_KEY
の取り扱い間違えて消してしまったりすると、credentialsの複合ができなくなり詰んでしまうので注意しましょう。
詰んでしまった場合はconfig/credentials.yml.enc
を削除してrails credentials:edit
で1から設定し直すと持ち直せる可能性があります。(チーム開発だとツラみがすごいかも…)
最後に
ActiveStorage手軽で便利なのですが、バリデーションやキャッシュの機能を持ち合わせていないとどこかでみたのでアップロード時にファイルチェックが必要な要件があったりすると扱いにくいかもしれません。
ただ厳密さが求められないような状況であれば素早く実装できるので検討してみても良さそうです!