Active Storage
Actrive Storageとは
Actrive Storageとは、ファイルアップロードを行うための機能です。この機能を使うことでフォームで画像の投稿機能などを簡単に作ることができます。
また画像などのファイルのアップロードを簡単にするメソッドが使用でき、画像を保存するテーブルを簡単に作成できます。
Amazon S3、Google Cloud Storage、Microsoft Azure Storageなどの クラウドストレージサービスへのファイルのアップロードや、ファイルをActive Recordオブジェクトにアタッチする機能を提供します。development環境とtest環境向けのローカルディスクベースのサービスを利用できるようになっており、ファイルを下位のサービスにミラーリングしてバックアップや移行に用いることもできます。
Active Storageの使用方法
$ rails active_storage:install $ rails db:migrate
このマイグレーションによって、active_storage_blobs
とactive_storage_attachments
という2つのテーブルが生成されます。
active_storage_blobs
はファイル名、ファイルの種類、バイト数、誤り検出符号などのメタデータを保持するモデルactive_storage_attachments
はBlobオブジェクトとActive Recordオブジェクトを紐付けるための中間テーブル
なおここで作成された2つのモデルはActive Storageを使う際に触れることはありません。なのでカラムの追加など行うこともありません。
事前にTweetモデルを作成しておき、このTweetモデルに画像を添付できるような実装を行っていきます。
※ Active Storageでは、モデルを作成する際に画像用のカラムを用意する必要はありません。
次のコードのようにhas_one_attached
を使うことで、Tweetモデルに画像を一枚添付できるようになりました。
class Tweet < ApplicationRecord has_one_attached :image end
:image
はファイルの名前で、好きなように変更することもできます。(例えば :avatar
、:photo
など)
以下のように書くことでTweetに画像をつけることができるようになります。
tweet_controller.rb class TweetController < ApplicationController def create user = Tweet.create!(tweet_params) redirect_to root_path end def show @tweet = Tweet.find(params[:id]) end private def tweet_params params.require(:tweet).permit(:body, :image) end end
tweet投稿フォーム。フォームのfile_field
で選択された画像をTweetモデルと紐付けています。
new.html.erb <%= form_with model: @tweet, local: true do |f| %> <%= f.text_area :body %> <%= f.file_field :image %> <%= f.submit %> <% end %>
tweet詳細画面。image.attached?
で特定のtweetがimageを持っているかどうかを調べられます。
show.html.erb <% if @tweet.image.attached? %> <%= image_tag @tweet.image %> <% end %>
Actice Storageの保存先の設定
ファイルの保存先は各環境の設定ファイルに記載します。利用するサービスをActive Storageに認識させるには必要な記述です。
config/environments/development.rb Rails.application.configure do config.active_storage.service = :local end
config/environments/test.rb Rails.application.configure do config.active_storage.service = :test end
Active Storageのサービスはconfig/storage.ymlで宣言します。アプリケーションが使うサービスごとに、名前と必要な構成を指定します。
開発環境(local)、テストともにDiskサービス(ローカルのディスク)を使うと宣言します。またtmp/storageディレクトリがファイルの保存先に指定されています。
config/storage.yml local: service: Disk root: <%= Rails.root.join("tmp/storage") %> test: service: Disk root: <%= Rails.root.join("tmp/storage") %>
RSpecテストで画像を添付する
事前にテストで使う画像をspec/fitures/image
にセットしておきます。
それでは実際に「作成済みのtweetに画像を添付できるか」というテストを書いてみます。
※ FactoryBotにtweetとuser、またLoginモジュールを作成している前提です。
tweets_spec.rb require 'rails_helper' RSpec.describe "Tweets", type: :system do let!(:tweet) { create :tweet } let(:user) { create :user } describe '画像投稿機能' do context '画像を添付する' do it '正常に添付することができる' do Login_as(user) visit tweet_path(tweet) attach_file 'tweet[image]', "#{Rails.root}/spec/fixtures/image/hoge.jpg" click_on '投稿する' expect(page).to have_selector("img[src$='hoge.jpg']") end end end
attach_file
を使うことで画像を添付するという操作をすることができます。