ino-akiのブログ

ITエンジニアを目指して学習したことをアウトプットするブログ

Rails 画像アップロード機能

画像アップロード機能実装

RailsActive Storageという機能を使用

ファイルアップロード機能を簡単に実装できるGem

 

画像加工ツールを導入

ImageMagick

コマンドラインから画像に処理を加えることができるツール

処理としては、画像の作成やサイズ変更、保存形式の変更などがある

ImageMagickはGemではなく、ソフトウェア

そのため、Homebrewからインストールする

GemではないImageMagickRubyRailsで扱うには、MiniMagickというGemが必要

 

MiniMagick

ImageMagickの機能をRubyで扱えるようにしてくれるGem

RailsImageMagickを扱うために必要

画像サイズの変更には、ImageProcessingというGemを追加する必要がある

 

ImageProcessing

MiniMagickでは提供できない、画像サイズを調整する機能を提供するGem

 

手順
ImageMagickをHomebrewからインストール

% brew install imagemagick

 

Gemをインストール
# Gemfileの一番下に記述
gem 'mini_magick'
gem 'image_processing', '~> 1.2'


% bundle install

 

画像処理にMiniMagickを使用するため、設定ファイルに記述

config/application.rbのclass Application内のconfig.~の下に追加

config.active_storage.variant_processor = :mini_magick

 

ローカルサーバーを再起動

% rails s

 

Active Storageをインストール

Active Storageに関連したマイグレーションが作成されます

% rails active_storage:install

Active Storageに関連したテーブルが追加される

% rails db:migrate


画像を保存

Active StorageのテーブルとMessagesテーブルのアソシエーションを定義messages_controller.rbにて、imageカラムの保存を許可

Messagesテーブルのレコードと画像を紐づけるためにhas_one_attachedというメソッドを利用

 

has_one_attached
各レコードとファイルを1対1の関係で紐づけるメソッド

has_one_attachedメソッドを記述したモデルの各レコードは、それぞれ1つのファイルを添付できる

 

imageという名前でアクセスできるようになった画像ファイルの保存を許可する実装

app/controllers/messages_controller.rb
 # 中略

  private

  def message_params
    params.require(:message).permit(:content, :image).merge(user_id: current_user.id)
  end


保存した画像を表示

image_tag

img要素を生成するRailsのヘルパーメソッド

 

# ファイルをモデルから指定する場合

<%= image_tag モデル.画像ファイル %>

<%= image_tag user.avatar %>

 

# app/assets/ディレクトリ下の画像ファイルパスでも指定できる

<%= image_tag 画像ファイルのパス %>

<%= image_tag "avatar.png" %>

 

このままの記述では、画像が存在しない場合でも、画像を表示する記述が読み込まれて、エラーを起こす

この問題を解決するために、メッセージに画像が添付されているかをチェックするattached?というメソッドを使用

<%= image_tag message.image, class: 'message-image' if message.image.attached? %>

ifを使って、要素の生成に条件をつけ、attached?メソッドで画像の添付をチェック

画像が存在する場合のみimage_tagが読み込まれるようになる

 

variant

Active Storageを導入している場合に使用可能なメソッド

variantメソッドを使用することで、ファイルの表示サイズを指定

モデル.ファイル名.variant(resize: '幅x高さ')

<%= image_tag message.image.variant(resize: '500x500'), class: 'message-image' if message.image.attached? %>