Sergey Makridenkov
Sergey Makridenkov

Reputation: 624

undefined method 'to_slice' for IO::ARGF (compile-time type is IO+)

I try to write AJAX uploaded image data:image/gif;base64,R0lGOD... into file via IO. Got strange exception

in src/controllers/product.cr:41: instantiating 'Base64:Module#decode(IO+, File)'
Base64.decode(photo_b64_io, file)
in /usr/share/crystal/src/base64.cr:173: undefined method 'to_slice' for IO::ARGF (compile-time type is IO+)
from_base64(data.to_slice) do |byte|

My code

  photo_b64_io = env.request.body.not_nil!
  photo_b64_io.gets(",") # seek to real data

  File.open(File.join(upload_path, file_path, file_id), "w") do |file|
    Base64.decode(photo_b64_io, file)
  end

How to improve?

Upvotes: 1

Views: 133

Answers (1)

Jonne Haß
Jonne Haß

Reputation: 4857

Base64.decode does not take an IO as first parameter, it takes something that responds to to_slice, so a String or a Slice usually.

You either have to read the entire IO into memory first before passing it to Base64.decode, using IO#gets_to_end (given it's base64 encoded data it should be safe to read into a String).

Or if you want to stay memory-efficient you should read in chunks of an multiple of 4 (since with base64 encoding every 3 original bytes are encoded into 4 bytes), using IO#read (ensure to loop until your chunk is full and handle the EOF case), and then decode each full chunk and write the result to a file before recycling your buffer for the next chunk.

Upvotes: 1

Related Questions