production.log

ピクスタ株式会社で開発部の部長をやっている星直史のブログです。

Rails 5.2でActive Storage を使った画像のアップロードを試す

概要

ひょんなことから、画像をアップロードする処理を書くことになりました。
これまで、Railsで画像アップロードといえば、CarrierWavePaperclipを使っておけば良いでしょ〜!くらいに思ってたんですが、せっかくRails5.2を使っているのであれば、Active Storageを使ってみよう!と思ったので、
今回はRails5.2でActive Storageの使った画像のアップロードの方法をまとめます。

なぜActiveStorageなのか

今回のアップロード機能の要件は至極単純でした。

  • あらかじめ、特定のフォルダに画像データが配置されている
  • 上記の画像データを特定のモデルにバッチで添付する
  • アップロードされた画像はオリジナルサイズで閲覧ができる

ただこれだけでした。 サムネイル作成などのファイルの変換、バリデーション、セキュリティなどなど、ガン無視でOKみたいな。 そのため、CarrierWavePaperclipは、やや機能過多感があるため、今回はActive Storageに決定しました。 また、Active Storageの特徴を抜粋すると下記の通りです。

  • DBにファイルのメタ情報と中間テーブルを用意することによって、既存のテーブルにカラムを追加しなくても良い => スキーマの変更が柔軟にできそう
  • レコード:ファイルが1:1にも1:多にもできる
  • 既存モデルにはhas_one_attached :nameと書くだけ。
  • 時間制限付きURLを楽に生成できる

今回の要件に置いてはこの機能があれば十分ですね。

Getting start

railsguides.jp ここ読めばGetting startできるわけですが、コマンドとかをまとめようと思います。

config/storage.ymlの編集

どこに保存すんの?という設定を書きます。

test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

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

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-west-2
 bucket: bucketname

amazonのところの書いた<%= Rails.application.credentials.dig(:aws, :access_key_id) %>については、Rails 5.2からのcredential管理の方法で設定した値を使います。 詳細はこちらの記事を参照してください。

blog.naoshihoshi.com

config/environments/development.rb

config/storage.ymlに設定したawsの設定を反映するために、config/environments/development.rbを修正します。

# Store uploaded files on the local file system (see config/storage.yml for options)
# config.active_storage.service = :local
config.active_storage.service = :amazon

モデルにファイル添付する設定を書く

冒頭で紹介した通り、1レコードにつき1ファイルだけ添付するのであれば、下記設定のみです。

class User < ApplicationRecord
  has_one_attached :avatar
end

ファイルの添付と確認

ファイルの添付と確認はrails consoleで確認します。

$ cd rails_root
$ bin/rails c
user = User.first
user.avatar.attached? #=> false
filepath = File.join(Dir.home, 'filename.jpg')
user.avatar.attach(
  io: File.open(filepath),
  filename: File.basename(filepath),
  content_type: 'image/jpg'
)
user.avatar.attached? #=> true

# アプリケーションを指すblobの永続URLを生成
include(Rails.application.routes.url_helpers)
default_url_options[:host] = 'localhost:3000'

url_for(user.avatar) #=> "http://localhost:3000/rails/active_storage/blobs/09Iiw63f495IkJ09IiwkJ09Iiw6IkJBaH19--7209IiwiZXxsLCJwdXIiOiJibG9iX2lkIn19--726eT09IiwbeaHBEUT09Iiwbe29513f4943f49513f49e4a9c55b4af76f5/filename.jpg"

上記の生成されたURLにアクセスすると画像を閲覧することができます。

まとめ

簡単な設定情報と、モデルにhas_one_attachedという記述を追加するだけでファイルのアップロード機能を作ることができました。さすがRailsですね。 要件によってはリサイズしなければならなかったり、バックグラウンドで処理しなければならなかったりするので、Gemを使うことを検討しなければならないのですが、今回は要件が少なかったため、Active Storageで十分でした。