QRコードを生成(RQRCode)しをCarrywaveでS3にアップロードしたらEncoding::UndefinedConversionError ("\x89" from ASCII-8BIT to UTF-8)エラーになった

環境

Rails 5.1

利用gem

やりたかったこと

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

処理の流れ

  • 自動生成したQRコードを tmpフォルダに一次保存。
  • uploderの要素に、tmpフォルダ内のファイルを読込む
  • 一次保存した tmpフォルダを削除する。

検証

# QRコードを生成
png_to_s = RQRCode::QRCode.new("【QRコードに変換する文字列】").as_png(size: 200).to_s

file_path = "#{QR_IMAGE_TMP_PATH}/qr_image_[ランダム文字列].png"
# ファイルをtmpフォルダに書き込む
File.write(file_path, png_to_s ) ←ここでエラー

self.qr_image = File.open(file_path)
self.save

# 削除処理
File.delete(file_path)

エラーメッセージ

Encoding::UndefinedConversionError ("\x89" from ASCII-8BIT to UTF-8)

class Encoding::UndefinedConversionError (Ruby 2.6.0)

QRコードの画像ファイルは[ASCII-8BIT]で、それを[UTF-8]に変換しようとしたときに、[UTF-8]に存在しない文字があった場合に起こるエラー。その[ASCII-8BIT]の文字は、[UTF-8]には対応してないよ!ということですね。

ネットにあまり情報が落ちてなかったので、IOクラス(Fileクラスの親クラス)のドキュメントを確認します。 class IO (Ruby 2.6.0) ※ドキュメント2.6ですが、検証環境は2.4です。

途中のサンプルで外部エンコーディングを指定できるのがわかります。

# nkfプロセスから得られる文字列を EUC-JP と指定する
# IO.new などと共通のオプションが指定できる
IO.popen("nkf -e filename", external_encoding: "EUC-JP"){|nkf_io|
  nkf_io.read
}

ソースコードを[ASCII-8BIT]で読み込めるようオプションを付けました。

File.write(file_path, png_to_s )
↓
File.write(file_path, png_to_s, external_encoding: "ASCII-8BIT" )

これでエラーはなくなり無事、tmpフォルダにファイルの保存ができました。
QRコードの保存方法は、もう少しスマートなやり方がありそうだけど今の私にはこれが限界。。頑張れ自分!

参考

Rails5のAPIモードで画像ファイルをS3にアップロードする。(carrierwave利用) - t-sanoブログ