とんてき

Ruby, Ruby on Railsやその周辺技術を中心に。ときどき趣味のことも。

画像アップロード機能「Active Storage」を使ってみた!

「Active Storage」とは

Rails5.2から登場したgemで、ActiveRecordモデルへの紐付けや、
クラウドストレージサービス(AWSGCP、Azure)へアップロードが非常に容易に行えるライブラリ。
現在は、画像アップロードには「CarrierWave」というgemが一番よく使われているが、
今後はこの「ActiveStorage」が使われることになると言われている。。。(本当?)

1. ActiveStorageを準備する

gemをインストールするためには以下のコマンドを実行します。

rails active_storage:install

そうすると、以下のようなマイグレーションファイルが作成されます。

xxxxxxxxxxxxxxxxx_create_active_storage_tables.active_storage.rb

このマイグレーションファイルの中身は以下のようになっています。

# This migration comes from active_storage (originally 20170806125915)
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
  def change
    create_table :active_storage_blobs do |t|
      t.string   :key,        null: false
      t.string   :filename,   null: false
      t.string   :content_type
      t.text     :metadata
      t.bigint   :byte_size,  null: false
      t.string   :checksum,   null: false
      t.datetime :created_at, null: false

      t.index [ :key ], unique: true
    end

    create_table :active_storage_attachments do |t|
      t.string     :name,     null: false
      t.references :record,   null: false, polymorphic: true, index: false
      t.references :blob,     null: false

      t.datetime :created_at, null: false

      t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
    end
  end
end

この中身を見ると、テーブルが2つ作成されていることがわかります。
それぞれどういう役割を果たすかを簡単に説明すると、以下のようになります。
active_storage_blobs ・・・ ActiveStorage::Blobというモデルと紐づいており、ファイルの実態以外の情報(識別キー、ファイル名、Content-type、ファイルのメタデータ、サイズ等)を管理するもの
active_storage_attachments ・・・ ActiveStorage::Attachmentというモデルと紐づいており、ActiveStorage::Blobとその他のモデルを繋げる中間的な役割を果たすもの

作成されたマイグレーションファイルは特にいじらずにマイグレートを実施します。

rails db:migrate

次にファイルの実態をどこで管理するか設定している箇所を見てきます。
config/environments/development.rb

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

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

「root: <%= Rails.root.join("storage") %>」という記述がありますが、
この部分がファイルの実態の保管場所を意味しています。(root直下のstorageディレクトリ)

2. 画像アップロードを実装する

models/post.rbの中に「 has_one_attached :image」を追記します。
例では、Postモデルに紐付けをしたかったので、post.rbの中に記述しました。
このように「ActiveStorage」をインストールし、テーブルを作成してしまえば、
他のテーブルは修正することがなく、下記のような一文でテーブル間の連携ができてしまいます。(めちゃ楽)
1ポスト1画像を紐付けたかったため、「has_one_attached」としましたが、
もし複数の画像を紐付けたい場合は「has_many_attached」を使えば良いです。

class Post < ApplicationRecord
  has_one_attached :image
end

アップロード機能の実装は普通の画像アップロードと変わりません。

<% f.label :image %>
<%= f.file_field :image, class: 'form-control' %>
end

あとは、アップロードした画像を表示させます。

<% if @post.image.attached? %>
  <%= image_tag @post.image %>
<% end %>
end

「image.attahed?」メソッドを使うことで、画像が添付されていない場合でもエラーを回避することができます。
(image_tagは画像がない場合エラーを表示する。)

おわりに

今回は、ローカル環境だけでの実装でしたが、これがAWS等のクラウドストレージサービスでもとても簡単に実装できてしまいます。
まだまだ新しい機能であり、バリデーションやキャッシュといった機能は現在備わっていないようです。
とても簡単に実装できますが、これらのことも踏まえて導入を検討したいですね!

ではまた!