はじめに
ECサイトを制作する課題に取り組んでいる際にActiveStorageについて調べたのでまとめました。
ActiveStorageとは
Active Storageは、ストレージサービスへのファイルのアップロードや、ファイルをActive Recordオブジェクトにアタッチする機能を提供します。
Active Storage の概要 - Railsガイド
ActiveStorageでできること
アップロードされたファイルをアタッチする
アップロードされたファイルをActiveRecordオブジェクトにアタッチさせることで、実際のテーブルにファイルのカラムがあるかのように扱うことができます。
itemsテーブル
name | price | description |
---|
上記のようなテーブルにアップロードされた画像をimage属性としてアタッチし
name | price | description | image |
---|
のような扱い方ができるようになり、
item.nameなどと同じようにitem.imageでattachさせた画像を表示させられるようになります。
ストレージに保存する
アップロードされたファイルの保存先として
Railsアプリ内(ローカル)の他にもクラウドストレージサービスなどを指定することができ、
画像投稿機能があるサイトなど、利用されていくごとにファイルが増えていくような場合はそのようなサービスと連携させて保存していくのが良さそうです。
その他
アップロードされたファイルの「ActiveRecordオブジェクトへのアタッチ」「ストレージへの保存」以外にvariantなどを利用して画像の変形などを行いたい場合には、別途gemのインストールが必要になります。
ActiveStorageの使い方
保存先の設定
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: <%= ENV['AWS_ACCESS_KEY'] %>
secret_access_key: <%= ENV['AWS_SECRET_KEY'] %>
region: <%= ENV['AWS_REGION'] %>
bucket: <%= ENV['AWS_BUCKET'] %>
のような記述があり、ここがアップロードされたファイルの保存先を指定しています。
ここに記述されている:test
,:local
,:amazon
の設定を別途production.rb
等の環境ごとの設定ファイルに指定することで利用できます。
(開発環境では:localに、本番環境では:amazonなどのクラウドストレージを利用するやり方が良いかと思われます)
開発環境の設定development.rb
では:localが保存先としてデフォルトで指定されています。
config/environments/
の
Rails.application.configure do
config.active_storage.service = :local
end
本番環境でクラウドストレージを利用する場合はproduction.rb
で
Rails.application.configure do
config.active_storage.service = :amazon
end
のように自身が用意したものに変更します。
(AWSなどのクラウドストレージに保存する場合は、認証情報を安全に管理するためにdotenv-railsなどのgemの利用が良さそうです。)
ここまで終わりましたら
$ rails active_storage:install
と
$ rails db:migrate
を実行します。
これでactive_storageを利用するための以下の3つのテーブルが作成されます。
active_storage_blobs
アップロードされたファイルのメタデータが保存されるテーブル
active_storage_attachments
blobとアタッチ対象のテーブルを結びつける中間テーブル
と
active_storage_variant_records
variantを利用して生成されたデータが保存されるテーブル
モデルとファイルの結びつけ
次に``app/models/○○.rb``にファイルとモデルを関連づけるように記述をします
一つのレコードが一つの画像を持つ場合
class Item < ApplicationRecord
has_one_attached :image
end
のように記述します。
一つのレコードが複数の画像を持つ場合は
has_many_attached :images
のように記述します。
:image
は実際に取り出すときに
user.imageのように記述する部分になるので自由に命名して大丈夫です。
登録フォームを作成する
viewに画像をアップロードできるフォームを作成します。
<%= form_with model: @item, url: items_path, method: :post do |f| %>
<p>
<%= f.label(:name, "商品名") %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label(:price, "値段 ") %>
<%= f.text_field :price %>
</p>
<p>
<%= f.label(:sku, "型番 ") %>
<%= f.text_field :sku %>
</p>
<p>
<%= f.label(:description, "説明 ") %>
<%= f.text_area :description %>
</p>
### 他の属性と同じように書けばよい。
<%= f.file_field :image %>
<p>
<%= f.submit "作成" %>
</p>
<p>
<%= link_to "戻る", items_path %>
</p>
<% end %>
コントローラーに記述
class ItemsController < ApplicationController
def create
@item = Item.new(item_params)
if @item.save
flash[:success] = '商品を登録しました。'
redirect_to admin_items_path
else
flash[:danger] = '商品の登録に失敗しました。もう一度試してください。'
render 'new', status: :unprocessable_entity
end
end
private
### :imageを追加
def item_params
params.require(:item).permit(:name, :price, :sku, :description, :image)
end
end
表示させる
<!-- items/show -->
<%= @item.name %>
<%= @item.price %>
<%= image_tag(@item.image) %>
variantの使い方
variantを使って、画像のリサイズを行う方法は2種類用意されています。
- 画像処理ライブラリとしてImageMagickを利用する
- 画像処理ライブラリとしてvipsを利用する
ImageMagickは、libvipsに比べて知名度が高く普及も進んでいます。しかしlibvipsは10倍高速かつメモリ消費も1/10です。JPEGファイルの場合、
libjpeg-dev
をlibjpeg-turbo-dev
に置き換えると[2〜7倍高速]になります。
Active Storage の概要 - Railsガイド
vipsを使ってみます。
使うための準備
vipsをインストールする
macなら
brew install vips
またはlibvips
(vipsの中にlibvipsも含まれています。)
Dockerを利用している場合、Dockerfileにlibvipsが含まれているか確認してください。含まれていれば、別途インストールは不要です
image_processingを入れる
次にGemfileに
gem "image_processing", ">= 1.2"
を記述してbundle installをします。
image_processingを入れることで
Rubyでimage_magickを使うために必要な"Mini_magick"、Rubyでvipsを使うために必要な"ruby-vips"もインストールされます。
補足
もしrails7以降にvariantでimage_magickを使う場合は
デフォルトの設定がvipsになっているため
config/application.rb
に
config.active_storage.variant_processor = :mini_magick
の記述が必要なようです。(rails7以前の場合は反対にvipsを利用する場合に記述が必要)
実際に使う
<%= image_tag @item.image.variant(resize_to_fit: [150, 150]) %>
のように記述をする方法と
例えば、商品のモデルapp/models/item.rb
に
class Item < ApplicationRecord
has_one_attached :image
def thumnail
image.variant(resize_to_limit: [450, 300])
end
def large
image.variant(resize_to_limit: [600, 700])
end
end
のように定義しておいて、viewで
<%= image_tag @item.thumnail %>
のように記述して使う方法があります。
variantの仕組み
最初にvariantが使用されているページにアクセスしたときに、
rails active_storage:install
を実行した時に作成されたactive_storage_variant_recordsテーブルにvariantで生成された加工後のデータが保存されます。
次回以降にアクセスした際は新たに生成せず、そのデータを読み込んで利用するため、処理が早くなる。
画像のリサイズにvariantを使うメリット
サーバー側でサイズの変更や加工などの画像処理をするためクライアント(ブラウザ)へ送信する画像のサイズを小さくすることができ、ページの読み込み速度を向上させられる。
ただし、画面の大きさに合わせて動的に画像サイズを変更できるわけではないのでCSSと合わせて使うのが良さそう。
さいごに
自分なりに学んだことをまとめてみました。間違っている箇所などありましたら指摘いただけると幸いです。