ActiveStorageを深掘る
ActiveStorageとは
ActiveStorageとは、Rails5.2で追加されたファイルアップローダーのこと。フォームでの画像投稿機能が簡単に実装できるようになる。(ImageMagicというソフトウェアやmini_magick、image-processingといったGemを入れておくと画像の編集やサイズ調整も簡単にできる)また、Amazon S3, Google Cloud Storage, Microsoft Azure Storageなどといった、クラウドストレージサービスへのファイルアップロードも簡単にできる。
要はいろいろと簡単にできる。ということ。
ただ、バリデーションが設定できるようになったのはわりと最近らしく、ActiveStorage以外にもcarrierwave、refile、dragonfly、shrineなどファイルアップローダーはいろいろ種類があり、ActiveStorageが際立って良い!かと言うとそこまでなのかなという感じ。
ActiveStorageの特徴
上述の通りファイルアップローダーはActiveStorageだけではない。そこで、ActiveStorageの特徴は何なのかを調べてみると、最大の特徴は、
ポリモーフィック関連を使って、ファイルのデータをBlobモデルとAttachmentモデルに集約させる作りになっている。
ということ。
よくわからん。てかポリモーフィック関連てなに。
と思ってしまった自分のために少し詳しく書いておくと、 Railsのようなオブジェクト指向の世界における意味としては、複数の異なるオブジェクトが同じメッセージに応答できるということ。ある1つのカラムが複数のテーブルを参照しているようなパターンの関連を表したもので、例えば、同じようなカラムを持っているテーブルが複数ある場合、それらを1つのテーブルで管理してしまうことができる。複数のクラスのインターフェースを統一し、同じように扱えるようにする。
フォームオブジェクト的なイメージで合ってるかな? 話が脱線しそうなので、ポリモーフィック関連はまた別で書こうと思います...。
ActiveStorageを使って画像を添付するには、
% rails active_storage:install
% rails db:migrate
コマンドを実行してインストールすると、
active_storage_blobs テーブル
active_storage_attachments テーブル という2つのテーブルを生成するマイグレーションファイルができる。
ActiveStorage::Blob
ActiveStorage::Blobモデルは添付されたファイルに対応していて、active_storage_blobsテーブルに添付画像のデータが管理されているイメージ。 またファイルの実体をデータベース外のストレージサービスで管理する。識別key、ファイル名、サイズなどといったをメタデータを管理している。
ActiveStorage::Attachment
このAttachment結合モデルを介して様々な関連付けをしている。ここに先程のポリモーフィック関連の話が関係していて、外部キーで多種多様な外交付き合いをしまくっているこのAttachmentくんはDBにとっては一つのアンチパターンともされている。
ふむふむ、ActiveStorageは、外交的で多様な関連付けをしてくるAttachmentくんと、内向的で堅実なBlobちゃんがしっかり細かいデータの管理をしているという、正反対の二人によって成立しているものなのかと超ざっくり思いました。ちなみに、AttachmentモデルはBlobオブジェクトとActive Recordオブジェクトを紐付けるための中間テーブルです。
基本的な使い方
いろいろ書いてみたけど、実際はActiveStorageで作られたマイグレーションファイルは触らなくて大丈夫です。 例えば、messageモデルに画像を添付したいときは
class Message < ApplicationRecord has_one_attached :image end
とアソシエーション設定する。 さらに、複数画像を添付したいときは、
class Message < ApplicationRecord has_many_attached :images end
とする。 複数画像を添付するときの注意点としては、
ビューファイルにおいてimageではなくimagesと複数形になること
file_fieldにオプションとして、multiple: true を追記すること
また、ストロングパラメーターに許可もらうようにするのも忘れないように。
ActiveStorageを使ったときのモデル単体テストコード
File/IO Objectsをアタッチする。 HTTPリクエスト経由では配信されないファイルをアタッチする必要が生じる場合があり、これを行うには、オープンIOオブジェクトとファイル名を1つ以上含むハッシュを渡す。 僕が使った例で言うと、テストコードを書く際のFactoryBotに定義するとき、テスト画像差し込みに使いました。 予めテスト用に差し込む画像をpublicディレクトリのimagesファイルに置いています。
FactoryBot.define do factory :message do content {Faker::Lorem.sentence} association :user association :room after(:build) do |item| item.image.attach(io: File.open('public/images/test_image.png'), filename: 'test_image.png') end end end
可能であれば、オプションでcontent_typeを追記してファイル形式までわかるようにしてあげると、判定がされやすいみたい。
終わりに
ほんとは作成中のアプリケーションでユーザーのアイコン画像と投稿に添付する画像を保存したいけど、ActiveStorage使ってたらその場合どうなるの?ってのを知りたかったのに、どんどん脱線して行っちゃった。でも、ActiveStorageに関して少し詳しくなれたし、ポリモーフィック関連とかいう新しい概念にも触れられたので良かった。いろいろ調べてみた感じできそうではあるけど、あんまりよろしくない方法になるのかなー。アプリ完成までにはなんとかしたい。