はじめに
CarrierWaveの備忘録。
Railsは5。
Brew
ImageMagickをあらかじめ入れておく。
画像をS3に置くだけなら要らないけど、たいていの場合は加工するはず。
brew install imagemagick
Gemfile
RailsからS3にアクセスするためのGemと画像加工用にRMgickを入れておく。
# 画像保存
gem 'carrierwave'
# For Carrierwave(S3用)
gem 'fog'
# 画像加工用
gem 'rmagick'
設定ファイル
S3の設定を記載しておく。
initializers/carrierwave.rb
# S3を使用しているかを判定するためのメソッド。(ローカル環境ではS3を使わないため)
def use_s3?
ENV['S3_ACCESS_KEY'] && ENV['S3_SECRET_KEY'] && ENV['S3_REGION'] && ENV['S3_BUCKET']
end
## CarrierWaveの設定
CarrierWave.configure do |config|
# S3の設定
if use_s3?
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => ENV['S3_ACCESS_KEY'],
:aws_secret_access_key => ENV['S3_SECRET_KEY'],
:region => ENV['S3_REGION'],
# :host => '必要なら設定する'
# :endpoint => '必要なら設定する'
}
# S3のバケットを指定。
config.fog_directory = ENV['S3_BUCKET']
# 一般公開させて無いS3の場合は以下の設定を行う。
config.fog_public = false
# 一般公開されていない場合は以下の設定をする事で60秒間有効なURLを発行してくれる。
config.fog_authenticated_url_expiration = 60
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/
end
# public配下にキャッシュができると参照されてしまうので、予め変えておく。
config.cache_dir = "#{Rails.root}/tmp/uploads"
end
モデル
画像はString
型で定義する。
migrate.rb
class Images < ActiveRecord::Migration[5.0]
def change
create_table :images do |t|
# 管理したい画像
t.string :image
# etc...
t.timestamps
end
end
end
model.rb
# 画像をアップロードする際のルール(別ファイルにしておけば汎用的に使える。)
class ImageUploader < CarrierWave::Uploader::Base
# S3を使用するか?
if use_s3?
storage :fog
else
storage :file
end
# S3やローカルの保存先。(以下の書式をそのまま書いておけば大抵問題無い)
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# 以下のようなことができる。
# リサイズしたり画像形式を変更するのに必要
include CarrierWave::RMagick
# 画像を100x100にリサイズする。
process :resize_to_fill => [100, 100]
# 保存形式をJPGにする
process :convert => 'jpg'
# サムネイルを生成する設定
# version :thumb do
# process :resize_to_fill => [40, 40, gravity = ::Magick::CenterGravity]
# end
# jpg,jpeg,gif,pngしか受け付けない
def extension_white_list
%w(jpg jpeg png)
end
# 拡張子が同じでないとPNGをJPGとかにコンバートできないので、ファイル名を変更
def filename
super.chomp(File.extname(super)) + '.jpg' if original_filename.present?
end
# 別のバケットにアクセスする場合は以下のようにする。
# https://blog.hello-world.jp.net/ruby/1449/
# def fog_directory
# config = YAML.load_file("#{Rails.root}/config/carrierwave.yml")[Rails.env]
# config['fog_another_directory']
# end
end
# 画像用モデル
class Image < ApplicationRecord
# ファイルアップロード処理
mount_uploader :image, ImageUploader
end
View
特に大した事はせず。
= simple_form_for(@image) do |f|
-#アップロードする画像(確認画面を作ることもできるけど、本記事では割愛)
= f.input :image, as: :file
-#アップロードした画像を表示
= image_tag f.image
-#カラム名にremoveをつけてデータを送ると画像を消せる。
= f.input :remove_image, as: :boolean
= f.submit "画像アップ"
Controller
StrongParamsなどいろいろ割愛。。。
def post_image
Image.new(params[:image]).save
end
まとめ
今まで自分でこれらのことをしてたけど、CarrierWave
を使うととても楽だった。
ただし、open
などでデータを取得して画像を設定したい場合にはややイレギュラーなことをする必要があった。
また、DBにblobとして格納する場合はCarrierWave
は使えない。
なので、要件に合わせて頑張る必要がある。
おまけ
URLから画像を拾ってきて画像を保存する方法。
もっといい方法があったら知りたい。
open(path, :allow_redirections => :safe) do |file|
# 一時的にテンポラリーファイルを作る必要があった。
temp_img_file = Tempfile.new('ファイル名')
temp_img_file.binmode
temp_img_file << file.read
temp_img_file.rewind
# UploadedFileもしくはCarrierWave::Uploader::Base形式にする必要がある。
uploaded_file = ActionDispatch::Http::UploadedFile.new(
filename: 'ファイル名',
type: file.content_type,
tempfile: temp_img_file)
image.image = uploaded_file
image.save
end
画像が横になる場合
以下のコードを記載する。
ImageUploader
process :fix_rotate
# 画像の向きを調整する。
def fix_rotate
manipulate! do |img|
img = img.auto_orient
img = yield(img) if block_given?
img
end
end