Ruby on Rails Learning Diary

学習したことの整理用です。

【Rails】Active Storageを使って画像をアップロードする

実装したいこと

以前、gemCarrier Waveを使って画像アップロード機能を実装しました。
今回は試しにActive Storageを使用してみたいと思います。
初めて使ったのですが、すごく簡単でした。
ただし、ファイルの形式のバリデーションやデフォルト画像の設定などの機能はついてないので不便さも感じました。

study-diary.hatenadiary.jp

Active Storageとは

Rails5.2から提供されるようになったファイルアップロード機能

Active Storage の概要 - Railsガイド

実装の流れ

  1. Active Storageのセットアップ
  2. ファイルをアップロードしたいModelの設定
  3. Viewの設定
  4. Contorollerの設定

Active Storageのセットアップ

$ rails active_storage:install

このコマンドでマイグレーションファイルが生成されるので、ターミナルでrails db:migrateします。

# 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
      t.foreign_key :active_storage_blobs, column: :blob_id
    end
  end
end

生成されるテーブルはそれぞれ、ActiveStorage::AttachmentActiveStorage::Blobモデルに紐付いています。

ActiveStorage::Blobは、アップロードした画像についての情報を管理するモデル

ActiveStorage::Attachment は、画像を扱う他のモデルとActiveStorage::Blobを結びつける中間テーブル的なモデル。ポリモーフィック関連となっている。

アップロードしたファイルの保存先設定

config/environments/development.rbでファイル管理場所を指定できます。

  #33行目あたり
  # Store uploaded files on the local file system (see config/storage.yml for options).
  config.active_storage.service = :local

今は、localが指定されています。localとはどこなのか更にみていきます。
コメント部分にあるように、config/storage.ymlを確認します。

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

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

service: Diskでローカル環境にファイルが保存される設定になっています。
今回はデフォルトの設定のまま進めていきます。

Model

今回は、Postモデルで画像を扱えるようにします。
各投稿に1つの画像を添付できるようにしたいので、has_one_attachedメソッドを使います。
多数添付したいときは、has_many_attachedを使います。

class Post < ApplicationRecord
  belongs_to :user
  has_one_attached :image #ここ

(略)
end

Views

入力フォームを整えていきます。

= form_with model:@post, local: true do |f|
  (略)
  .form-group
    = f.label :image
    = f.file_field :image, class: 'form-control'
  = f.submit nil, class: 'btn btn-primary'

画像を表示したい部分には以下のコードを使います。

= image_tag post.image.variant(resize_to_limit: [300,200]) if post.image.attached?

image_tagは、画像が添付されていないときはエラーになるので、ifで判定文をつけてあげます。

variant(resize_to_limit: [300,200])でサイズを指定しています。
この機能を使いたい場合は、Gemfileの以下のgemコメントアウトを外す必要があります。

# Use Active Storage variant
gem 'image_processing', '~> 1.2'

Contoller

Strong Parameterで弾かれないように、imageのパラメーターも許可するように設定しておきます。

(略)
def post_params
    params.require(:post).permit(:title, :body, :image)
end

完成

f:id:Study-Diary:20201017200342p:plain
投稿フォーム
f:id:Study-Diary:20201017200400p:plain
投稿したもの