I'm having trouble calling image.write with MiniMagick on a decoded base64 image in Rails. Every line seems to be working properly except for image.write. The code below is in my Rails API ImageController, which my React frontend is hitting through a POST request with the encoded image.
def create
uploaded_io = params["image_io"]["base64"] # base64 string + metadata
metadata = uploaded_io.split(',/')[0] + "," # "data:image/jpeg;base64,"
filetype = metadata.split("/")[1].split("base64")[0][0...-1] # "jpeg"
base64_string = uploaded_io[metadata.size..-1] # base64 string w/o metadata
blob = Base64.decode64(base64_string)
image = MiniMagick::Image.read(blob)
image.write `#{Time.new.to_i}.#{filetype}`
storage = Google::Cloud::Storage.new(
project_id: ENV['GOOGLE_CLOUD_PROJECT'],
credentials: JSON.parse(File.read('config/google_cloud_credentials.json'))
)
bucket = storage.bucket "auto-stock-189103.appspot.com"
bucket.create_file image,`test/#{Time.new.to_i}.jpg`
end
I added comments to the first few lines in the code describing their value. base64_string was too long to comment, so here is its value:
"/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABkAAD/4QMtaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTNDQjQyRjlEQTAxMTFFN0E4N0VBNzdGODEwREFGMTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTNDQjQyRkFEQTAxMTFFN0E4N0VBNzdGODEwREFGMTYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoxM0NCNDJGN0RBMDExMUU3QTg3RUE3N0Y4MTBEQUYxNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoxM0NCNDJGOERBMDExMUU3QTg3RUE3N0Y4MTBEQUYxNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pv/uAA5BZG9iZQBkwAAAAAH/2wCEAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQECAgICAgICAgICAgMDAwMDAwMDAwMBAQEBAQEBAgEBAgICAQICAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA//AABEIAAoACgMBEQACEQEDEQH/xABNAAEBAAAAAAAAAAAAAAAAAAAACQEBAQEAAAAAAAAAAAAAAAAAAAkKEAEAAAAAAAAAAAAAAAAAAAAAEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCMKU7f4AAA/9k="
Testing it here renders the correct image (a red square), but when I run the image.write
line it returns the following error:
bin/rails: No such file or directory - 1513397345.jpeg
*** NoMethodError Exception: undefined method `write' for nil:NilClass
nil
Here's the return value of image = MiniMagick::Image.read(blob)
for reference:
#<MiniMagick::Image:0x00007f9ba76ba1f8 @path="/var/folders/pf/xhvv11092_j08hw47q6rt9z80000gn/T/mini_magick20171215-26353-l2lcyu", @tempfile=#<Tempfile:/var/folders/pf/xhvv11092_j08hw47q6rt9z80000gn/T/mini_magick20171215-26353-l2lcyu (closed)>, @info=#<MiniMagick::Image::Info:0x00007f9ba76ba1d0 @path="/var/folders/pf/xhvv11092_j08hw47q6rt9z80000gn/T/mini_magick20171215-26353-l2lcyu", @info={}>>
Ultimately, my goal is to upload the image to Google Cloud so please let me know if there's a better way to go about this. I'm following this answer from a similar question, which is why I have it structured this way.
I think your problem is that you're using backticks where you mean to use double quotes:
image.write `#{Time.new.to_i}.#{filetype}`
# ----------^----------------------------^
Backticks will attempt to execute their contents in the shell. You don't have an executable file named 1513397345.jpeg
(which is what #{Time.new.to_i}.#{filetype}
evaluates to) so you get an error.
You just want to use plain old double quotes to get the string interpolation you're expecting:
image.write "#{Time.new.to_i}.#{filetype}"
and again a few lines below that:
bucket.create_file image, "test/#{Time.new.to_i}.jpg"
Furthermore, you probably want to store that filename in a variable because Time.new.to_i
isn't guaranteed to be the same in both invocation:
name = "#{Time.new.to_i}.#{filetype}
image.write name
#...
bucket.create_file image, name
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments