CarrierWave + Rails 5.1で画像アップローダー


Ruby on Railsのフォームから画像をサーバにアップロードするしくみをRubyGems『CarrierWave』を使って実装します。
またImageMagickを使って画像のリサイズをしたり、フォームのアップロード時に画像サイズのバリデーションにもトライしてみます。

🏀 CarrierWaveの画像アップローダーを作成

ImageMagickのインストール

画像の加工を行うためのライブラリImageMagickをインストールします。
Macの場合は次のコマンドをコマンドラインから実行します。

brew install imagemagick

Gemfileの登録

Gemfileに以下を追加して、bundle installを実行。

# Image Uploader
gem 'carrierwave'
gem 'rmagick', require: 'RMagick'

CarrierWaveのアップローダーを作成

次のコマンドを実行してCarierWave用のクラスapp/uploaders/image_uploader.rbを生成します。

# scaffold で Productに関する一式を作成
rails g scaffold product name:string image:text

# アップローダーを作成
rails g uploader image

アップローダーの記述を修正

先ほど生成されたimage_uploader.rbを次のように書き換えます。

# app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick

storage :file

process convert: 'jpg'

# 保存するディレクトリ名
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end

# thumb バージョン(width 400px x height 200px)
version :thumb do
process :resize_to_fit => [400, 200]
end

# 許可する画像の拡張子
def extension_white_list
%W[jpg jpeg gif png]
end

# 変換したファイルのファイル名の規則
def filename
"#{Time.zone.now.strftime('%Y%m%d%H%M%S')}.jpg" if original_filename.present?
end
end

Modelのカラムにアップローダーを紐付け

ModelProduct.imageと、アップローダーImageUploaderとをひも付け。

# app/models/product.rb
model Product
# ↓ 以下を追加
mount_uploader :image, ImageUploader
end

view/formへの追加

viewのformに以下を追加。

# app/views/products/_form.html.haml
form_for(@product) do |f|
# ↓ 以下を追加
= f.file_field :image
end

view表示側への追記

アップロードした画像をviewで表示させる場合は以下を追記してください。

# app/views/products/show.html.haml
= image_tag @product.image_url(:thumb)

以下を追加して、テーブルを作成。

bundle exce rake db:migrate

🎉 補足: 画像のサイズのバリデーション

アップロードする画像のサイズをチェックするバリデーション(validation)です。今回は幅400px, 高さ400pxより小さい場合にバリデーションでエラーが出るようにします。

まずはバリデーションの記述を追記。

# app/models/product.rb
class Product < ActiveRecord::Base
# ↓ これらを追記
# ------------------------------------------------------------------
# Validations
# ------------------------------------------------------------------
validate def check_image_dimensions
if geometry[:width] < 400 || geometry[:height] < 400
errors.add :image, '400x400ピクセル以上のサイズの画像をアップロードしてください'
end
end

# ------------------------------------------------------------------
# Public Instance Methods
# ------------------------------------------------------------------
def geometry
@geometry ||= _geometry
end

private
# ------------------------------------------------------------------
# Private Instance Methods
# ------------------------------------------------------------------
def _geometry
if image.file and File.exists?(image.file.file)
img = ::Magick::Image::read(image.file.file).first
{ width: img.columns, height: img.rows }
end
end
end

これで、アップロードした画像が幅400px, 高さ400pxより小さい場合はエラーが出ます。

🎃 補足:simple_formでプレビュー表示させる場合

simple_form』はformの記述がスッキリするgemです。
このsimple_formCarrierWaveを連携させる手順です。

Gemfileの登録

Gemfileに以下を追加して、bundle installを実行。

# Form Helper
gem 'simple_form'

プレビュー表示を行うフォーム

次のコードを書きます。

# app/inputs/image_preview_input.rb
class ImagePreviewInput < SimpleForm::Inputs::FileInput
def input
# :preview_version is a custom attribute from :input_html hash, so you can pick custom sizes
version = input_html_options.delete(:preview_version)
out = '' # the output string we're going to build
# check if there's an uploaded file (eg: edit mode or form not saved)
if object.send("#{attribute_name}?")
# append preview image to output
out << template.image_tag(object.send(attribute_name).tap {|o| break o.send(version) if version}.send('url'))
end
# allow multiple submissions without losing the tmp version
out << @builder.hidden_field("#{attribute_name}_cache").html_safe
# append file input. it will work accordingly with your simple_form wrappers
(out << @builder.file_field(attribute_name, input_html_options)).html_safe
end
end

でもって form 側は次のように書きます。

# app/views/products/_form.html.haml
# ↓ こんな感じでコードを修正
= simple_form_for @product do |f|
= f.input :image, as: :image_preview, input_html: { preview_version: :thumb }

すると、アップロード済のデータを編集する際に、formでpreview画像が表示されます。

🐡 参考リンク

🖥 VULTRおすすめ

VULTR」はVPSサーバのサービスです。日本にリージョンがあり、最安は512MBで2.5ドル/月($0.004/時間)で借りることができます。4GBメモリでも月20ドルです。 最近はVULTRのヘビーユーザーになので、「ここ」から会員登録してもらえるとサービス開発が捗ります!

📚 おすすめの書籍