Base64でQRコードを生成(RQRCode)して、S3にアップロード(carrierwave)する

環境

Rails 5.1

gem

やりたかったこと

セミナーのチケット管理システムを作っており、今回はチケット登録後に参加申込みができるQRコードを生成し、S3にアップロード(carrierwaveを使う)したい

プログラム

Tempfile.create do |t|
  t.binmode

  base64_data = RQRCode::QRCode.new("https://xxxxx.net").to_img.to_data_url
  decoded_data = Base64.decode64(base64_data.sub(%r/data:((image|application)\/.{3,}),/, ''))
  t.write decoded_data
  
  image_params = { filename: decoded_data.hash.to_s, type: "image/jpeg", tempfile: t }
  self.qr_image = ActionDispatch::Http::UploadedFile.new(image_params)
  self.save!
end

解説

Tempfile.create do |t|
end

Tempfile.new ・・で処理すると、ガバレージコレクションの関係でclosed streamになってしまうようなので、createで対応しています。createの場合、ブロックから出るときにファイルを削除してくれます。


t.binmode

t.writeするとき、バイナリファイルを渡すよ、と宣言しないとEncoding::UndefinedConversionError ("\x89" from ASCII-8BIT to UTF-8)のエラーがでます。。


base64_data = RQRCode::QRCode.new("https://xxxxx.net").to_img.to_data_url

RORCodeを使って、base64でコンバートした値を生成(data:image/png;base64・・ というやつ)します。

decoded_data = Base64.decode64(base64_data.sub(%r/data:((image|application)\/.{3,}),/, ''))
t.write decoded_data

それの頭のdata:image/png;base64,を削除したものをdecodeして、tempfileに書き出す。


image_params = { filename: decoded_data.hash.to_s, type: "image/png", tempfile: t }
self.qr_image = ActionDispatch::Http::UploadedFile.new(image_params)
self.save!

carrierwaveを使ってDBに保存する際はActionDispatch::Http::UploadedFileのオブジェクトで渡す必要があります。(formでファイルを送るときはこのオブジェクトで受け取ります。) parameterは - filename - type - tempfile を指定します。


これで保存ができました。お疲れ様です。