Madogiwa Blog

主に技術系の学習メモに使っていきます。

RubyonRails:rails5.2の新機能「ActiveStrage」で画像アップロード処理をお手軽に実装してみる

Rails5.2でActiveStrageというファイルアップロード系の機能が新しく追加されましたね(・∀・)
ちょっと自分が作っているアプリで使ってみたので使い方をφ(..)メモメモ

ActiveStrageとは?

ActiveStrageとは、Rails5.2から実装されたファイルアップロード機能です。
今までは画像等をアップロードするときにはCarrierWaveShrineといったGemを使うことが多かったと思いますが、それがRailsだけで簡単に出来るようになりました🙌

railsguides.jp

ActiveStrageを使ってみた

ソースだけ見たい方はこちら👀

github.com

準備

まずはActiveStrageを使うために下記コマンドを実行します。

$ rails active_storage:install
$ rails db:migrate

そして、ファイルのアップロード先を設定します。アップロード先はconfig.active_storage.serviceに設定されたkeyでstarage.yamlを参照します。

strage.yml

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

development.rb

  # Store uploaded files on the local file system (see config/storage.yml for options)
  config.active_storage.service = :local

ファイルをアップロードしてみる

まずはModelにファイルのプロパティを定義します。1つのファイルをアップロードする場合はhas_one_attached、複数のファイルをアップロードする場合はhas_many_attachedを使用します。

class User
  has_one_attached :avatar
end

次にcontrollerとviewを次のように実装します。
新規登録の場合は、パラメーターにavatorを追加してnewの引数に渡してあげるだけでいいのですが、既存レコードにファイルを設定する場合は.avatar.attachを使用する必要があります。

controller

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user, notice: message('user', 'create')
    else
      render :new
    end
  end

  def update
    @user = User.find(current_user.id)
    @user.avatar.attach(params[:user][:avatar])
    if @user.update(user_params)
      redirect_to @user, notice: message('user', 'update')
    else
      render :edit
    end
  end

  private

  def user_params
    params.require(:user).permit(:email, :name, :password, :password_confirmation, :avatar)
  end

view

= form_for @user do |f|
  %div.form-group
    = f.label :avatar
    = f.file_field :avatar, class: 'file-inputs'
  .actions
    = f.submit t('common.save'), class: 'btn btn-primary'

これで、画面からアップロードが出来るようになりました!!(・∀・)

バリデーションを実装してみる

しかし、このままでは画像以外がアップロードされてしまったり、大きなファイルがアップロードされてしまうといったことが防げません。。。
ActiveStrageは、まだvalidationの機能が無いので、自分で実装する必要があります😥

今回は、サイズのチェックと画像のみをアップロード可能とするようなバリデーションをサンプルとして載せましたので、参考までに。

class User < ApplicationRecord
  validate  :file_validation, if: -> { avatar.attached? }

  private

  def file_validation
    if avatar.blob.byte_size > 1_000_000
      file_raise_error('のファイル容量が大きすぎます')
    elsif !avatar.blob.content_type.starts_with?('image/')
      file_raise_error('は、画像以外はアップロード出来ません')
    end
  end

  def file_raise_error(message)
    avatar.purge
    errors.add(:avatar, message)
  end
end

おわりに

ActiveStrageはシンプルなファイルアップロード機能を実装するのであれば、お手軽に実装出来てよさそうに感じました(・∀・)
しかし、バリデーションを独自で実装する必要があるため、あまり複雑なアップロード処理にはまだ向かなそうですね😥

参考

tech.unifa-e.com

railsguides.jp

stackoverflow.com