write ahead log

ロールフォワード用

Rails5とCarrierWaveを使って画像アップロード機能を作る

以前はgemなしで実装したので今度はCarrierWaveを使ってみる.

あとはせっかくなので画像のリサイズなんかも試す.

インストール

CarrierWaveで画像のリサイズなんかをやるためにはRMagickやMiniMagickが必要になります.

で, これらはImageMagickのラッパーなのでやっぱりImageMagickが必要になります.

Ubuntu(WSL)の場合.

$ sudo apt install imagemagick
$ sudo apt install libmagick++-dev

サンプルプロジェクトを作成

$ rails new carrier_wave_sample

Gemfileを編集

今回はCarrierWave推奨のmini_magickを使います.

gem 'carrierwave'
gem 'mini_magick'

bundleでインストール.

$ bundle install

とりあえず足場を作る

前回同様, scaffoldで.

とりあえず掲示板っぽいものを作成.

メッセージ毎に画像を1つ登録できるようにする.

$ rails g scaffold message message:string image_path:string
$ rails db:migrate

uploaderを作る

uploaderはcarrierwaveで画像をアップロードする際の設定を行うイメージです.

CarrierWaveではRailsのgenerateコマンドに追加が行われて,

$ rails g uploader [アップローダー名]

が利用できるようになりますのでこれで作成します.

以下のようにしました.

$ rails g uploader MessageImage

アップローダーはapp/uploadersフォルダが新しく作られてそこへまとめられます.

今回生成されたものを見てみると以下のようになっています.

class MessageImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  storage :file
  # storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
  [中略]

store_dirメソッドはファイルの保存先かな?とかある程度想像がつくのでわかりやすそうではあります.

Uploaderとモデルを関連付ける

モデルに画像のパスを保存するので, 今回作成したUploaderとモデルを関連付ける必要があります.

class Message < ApplicationRecord
  mount_uploader :image_path, MessageImageUploader
end

viewの編集

追加側

scaffoldで作ったビュー(_form.html.erb)のファイルパスの部分をfile_fieldに変更.

  <div class="field">
    <%= form.label :image_path %>
    <%= form.file_field :image_path, id: :message_image_path %>
  </div>

表示側

表示側(show.html.erb)も変更.

<p>
  <strong>Image path:</strong>
  <%= image_tag(@message.image_path_url) %>
</p>

ここまででアップロードと表示ができるようになります.

簡単.

アップロードした画像はpublic/の下にstore_dirメソッド定義通りのパスで作成されていました.

画像をリサイズする

今回は画像の変換にMiniMagickを使うのでコメントを外しておきます.

app/uploader/message_image_uploader.rbを変更.

class MessageImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick

  process resize_to_fit: [200, 200]

resize_to_fitは縦横比を維持したままリサイズするメソッドです.

上記では200×200のサイズになるようにアップロード時に変換するようにしています.

Module: CarrierWave::MiniMagick

リファレンスを見ると他にもいくつかメソッドがありますがよくわからんなぁと思っていたところ詳しく記載してくださっている方がいらっしゃったのでリンク張っときます.

麺処 まつば - CarrierWave + RMagick 画像のリサイズをまとめてみました

サムネイルを作る

アップロードした画像とは別にサムネイルを作る事もできます.

元々コメントアウトで記述されているのでアンコメントするだけで使えます.

  # 以下
  # Create different versions of your uploaded files:
  version :thumb do
    process resize_to_fit: [50, 50]
  end

表示するには以下の様にビューを変更します.

app/views/messages/show.html.erbを変更.

<!-- 以下を追加 -->
<p>
  <%= image_tag(@message.image_path_url(:thumb)) %>
</p>

[モデル名][画像パス保存の属性名]_urlのメソッドには引数にversionのシンボルが渡せます.

今回は:thumbを追加したので引数にこれを渡す事で作成したサムネイルの画像パスを取得できます.

画像をバリデーションする

拡張子でのバリデーション

こちらもコメントアウトをアンコメントするだけで使えます.試しにpngを禁止してみました.

バリデーションで引っかかるので便利です.

app/uploaders/message_image_uploader.rbを編集.

  def extension_whitelist
    %w(jpg jpeg gif)
  end

画像サイズでのバリデーション

画像ファイルの上限サイズを指定できます.

app/uploaders/message_image_uploader.rbを編集.

  def size_range
    1..5.megabytes
  end

I18Nの対応

エラーのバリデーションメッセージを日本語化したいところです.

公式に記載がありました.

これだけできれば色々できそうです.