hello-world
webエンジニアのメモ。とりあえずやってみる。

[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形式でのアップロードが可能になりました。

参考


Related #carrierwave

[rails]carrierwaveで保存した画像のurlを取得する

carrierwave 0.10.0 で確認 imageカラムにcarrierwaveで保存した画像を保存している場合、デフォルトのままだとだとurlメソッドを実行してもpublic以下のパスのみで http://~ が設定されていません。

[Rails]carrierwaveのcallbackをskip

Railsで画像アップロード機能を作る際に欠かせないgemと言えば carrierwave ですが、save時にcarrierwaveのcallbackをskipしたい場合の対応方法をメモしておきます。

[rails]carrierwaveを使って画像を保存するAPIサンプル

Ruby 2.1.4, Rails 4.1.7 で確認 画像アップロード機能を作成する際に carrierwaveをよく使うのですが毎回調べているので基本的な設定部分のメモを残しておきます。