[rails]base64エンコードされた画像をcarrierwaveに保存する
Ruby 2.1.4, Rails 4.1.7 で確認 前回はcarrierwaveを使ってPOSTされた画像ファイルの保存を行うAPIを作ってみました。
今回はファイルではなく、base64エンコードされた画像データをpostして保存するのを試してみました。
ファイルアップロードを行った画像を、jsでcanvasを使って編集しbase64形式で再度アップロードする、といった際に使えると思います。
前回のcontrollerに機能を追加します。
1. base64形式の画像データを保存できるようにする
- concern追加
app/controllers/concerns以下に carrierwave_base64_uploader.rb として以下のファイルを保存します
module CarrierwaveBase64Uploader
extend ActiveSupport::Concern
private
def base64_conversion(uri_str, filename = 'base64')
image_data = split_base64(uri_str)
image_data_string = image_data[:data]
image_data_binary = Base64.decode64(image_data_string)
temp_img_file = Tempfile.new(filename)
temp_img_file.binmode
temp_img_file << image_data_binary
temp_img_file.rewind
img_params = {:filename => "#{filename}.#{image_data[:extension]}", :type => image_data[:type], :tempfile => temp_img_file}
ActionDispatch::Http::UploadedFile.new(img_params)
end
def split_base64(uri_str)
if uri_str.match(%r{data:(.*?);(.*?),(.*)$})
uri = Hash.new
uri[:type] = $1
uri[:encoder] = $2
uri[:data] = $3
uri[:extension] = $1.split('/')[1]
return uri
else
return nil
end
end
end
- user_controllerにupdate_base64アクションを追加
concernをincludeするとbase64画像保存メソッドがuserコントローラ内で使用可能になります。
# app/controllers/user_controller.rb
class UserController < ApplicationController
include CarrierwaveBase64Uploader
def update
raise ArgumentError, 'invalid params' if params[:name].blank? || params[:profile].blank?
user = User.find_or_create_by(name: params[:name])
user.profile_image = params[:profile]
user.save!
render json: {
name: user.name,
profile_url: user.profile_image.url
}
end
def update_base64
raise ArgumentError, 'invalid params' if params[:name].blank? || params[:profile].blank?
user = User.find_or_create_by(name: params[:name])
user.profile_image = base64_conversion(params[:profile_base64])
user.save!
render json: {
name: user.name,
profile_url: user.profile_image.url
}
end
end
updateアクションとupdate_base64アクションはほとんど同じなので処理をまとめます。
とりあえずprivateメソッドにまとめましたがこんな感じでいいんでしょうか。。。
# app/controllers/user_controller.rb
class UserController < ApplicationController
include CarrierwaveBase64Uploader
def update
raise ArgumentError, 'invalid params' if params[:name].blank? || params[:profile].blank?
user_update
update_response
end
def update_base64
raise ArgumentError, 'invalid params' if params[:name].blank? || params[:profile_base64].blank?
user_update
update_response
end
private
def user_update
@user = User.find_or_create_by(name: params[:name])
@user.profile_image = params[:profile] ? params[:profile] : base64_conversion(params[:profile_base64])
@user.save!
end
def update_response
render json: {
name: @user.name,
profile_url: @user.profile_image.url
}
end
end
- routing追加
# config/routes.rb
Rails.application.routes.draw do
post 'user/update'
post 'user/update_base64'
end
とりあえずこれでbase64エンコード画像のアップロードAPIができました。
2. curlコマンドでAPIにアクセスしてみる
- アプリケーション起動
./bin/rails s
- base64エンコード画像を作成
irb -r base64 -r open-uri
'data:image/png;base64,' + Base64.strict_encode64(open('https://blog.hello-world.jp.net/wp-content/plugins/social-media-widget/images/default/64/twitter.png').read)
出力された文字列をコピーしておきます。
(base64エンコード画像作成の詳細に関しては こちらを参照)
- curlで画像アップロード
curl -F 'name=test' -F 'profile_base64=base64文字列を貼る' http://localhost:3000/user/update_base64
# {"name":"test","profile_url":"http://localhost:3000/uploads/user/profile_image/1/base64.jpeg"}
APIのレスポンスに書いてあるprofile_urlをブラウザで開いてみると、画像がアップロードされていることを確認できます。
これでファイルアップロード、およびbase64形式でのアップロードが可能になりました。