0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Request specでbase64を用いた画像のdecodeに躓いた

Last updated at Posted at 2021-03-22

Reactで実装したフロントエンドから画像をコントローラーに送ってActiveStorageに保存したい

Rails × React SPAの作成に当たり画像データをActiveStorageで扱いたい。しかしActiveStorageに保存するデータ形式は
reactで直接扱えないのでBase64を用いたencodingとdecodeを用いて保存を行う。

//画像は事前にvalueを取得できないのでFileReaderを使ってデータを読み取る
const file = e.target.files[0];
const reader = new FileReader()
reader.onload = () => { 
//以下2つはactivestorageの保存に必要
user.avatar.data = reader.result
user.avatar.filename = file.name 
}
reader.readAsDataURL(file) //戻り値はata:image/jpeg;base64,/9j/4AA…のようになる。これをサーバーサイドで複合する            

こんな感じの記述でフロント側で画像を読み込むとbase64形式でdataが取得できる。
サーバーサイドではこれを復号化する形でActiveStorageに画像を保存する。

def create 
  @user = User.new(sign_up_params)
  if @user.valid?
    if params[:user][:avatar][:data] != "" && params[:user][:avatar][:filename] != "" #画像データ自体は送られてくるので中身が空かどうか判定をする
      blob = ActiveStorage::Blob.create_after_upload!(
        io: StringIO.new(decode(params[:user][:avatar][:data]) + "\n"), #UserModal.jsxでfilereaderを使って取得した文字列を復号する
        filename: params[:user][:avatar][:filename] #filenameはUserModal.jsxで取得
        )
      @user.avatar.attach(blob) #先に作っておいた画像とuserを紐付ける
    end

実際フロントからは画像をbase64形式でencodeした文字列dataと、ファイルの名前filenameをリクエストとして送信するため
実行環境やsystem specについては問題なく通っていた。しかしrequest specではうまく通らなかった。

自分が今まで知っていた画像を添付する方法は

FactoryBot.define do
  factory :user do
    nickname {Faker::Name.name}
    email {Faker::Internet.free_email}
    password {'Pass1234'}
    password_confirmation {'Pass1234'}
    
    after.build do |user|
      user.avatar.attach
  end
end

のようにfactorybotでafter callbackを用いる方法か

user.avatar = fixture_file_upload('spec/fixtures/test_image.jpg', filename: 'test_image.jpg', content_type: 'image/jpg') 

のような記述をテストコード上で挿入するかのどちらかだった。

しかしこれらはbase64を用いた形式に合わず、いろいろ不都合だったので修正。

①画像データをencodeした文字列を取得

このサイトで画像データをbase64形式にencodeできる。
ここで取得した文字列をspec/fixturesに test_image.jpg.bin のような形式で保存

②encodeした画像データをテストコード上で読み込む

Base64形式の文字列は

user_params[:avatar][:data] = File.read('spec/fixtures/test_image.jpg.bin') #base64形式でコントローラーで扱うため、encode舌文字列をパラメータにセット

このようにFile.readを使うことで読み込むことができる。

こうすることで無事テストが通った。実行環境の動きにも近いのでより保守性も高まったと言えると思う。やったね

注意点

modelテストやsystemテストではあくまで画像データを直接読み込むので、画像データそのものは残しておく。

参考

RSpecで、Base64エンコードされた画像ファイルをテストする
https://www.malanka.tech/entry/2020/07/18/070000

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?