What is the best way to upload an image from a client to a Rails backend using Carrierwave. Right now our iOS developer is sending in the files as base64, so the requests come in like this:
"image_data"=>"/9j/4AAQSkZJRgABAQAAAQABAAD/4QBYRXhpZgAATU0AKgAAAAgAAgESAAMAAAABAAEAAIdpAAQAAAABAAAAJgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAHqADAAQAAAABAAAAHgAAAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAAeAB4DAREAAhEBAxEB/8QAHwAAAQUBAQE....
So, my question is really two questions. Should I tell him to send in a different file format? If base64 is the right way to send these files in, then how do I deal with them in carrierwave?
I think that one solution can be to save the decoded data to file and then assign this file to mounted uploader. And after that get rid of that file.
The other (in-memory) solution can be this one:
# define class that extends IO with methods that are required by carrierwave
class CarrierStringIO < StringIO
def original_filename
# the real name does not matter
"photo.jpeg"
end
def content_type
# this should reflect real content type, but for this example it's ok
"image/jpeg"
end
end
# some model with carrierwave uploader
class SomeModel
# the uploader
mount_uploader :photo, PhotoUploader
# this method will be called during standard assignment in your controller
# (like `update_attributes`)
def image_data=(data)
# decode data and create stream on them
io = CarrierStringIO.new(Base64.decode64(data))
# this will do the thing (photo is mounted carrierwave uploader)
self.photo = io
end
end
You can easily achieve that using Carrierwave-base64 Gem you don't have to handle the data yourself, all you do is add the gem and change your model from
mount_uploader :file, FileUploader
to
mount_base64_uploader :file, FileUploader
and thats it, now you can easily say:
Attachment.create(file: params[:file])
Old question but I had to do a similar thing, upload image from base64 string which was passed on via a json request. This is what I ended up doing:
#some_controller.rb
def upload_image
set_resource
image = get_resource.decode_base64_image params[:image_string]
begin
if image && get_resource.update(avatar: image)
render json: get_resource
else
render json: {success: false, message: "Failed to upload image. Please try after some time."}
end
ensure
image.close
image.unlink
end
end
#some_model.rb
def decode_base64_image(encoded_file)
decoded_file = Base64.decode64(encoded_file)
file = Tempfile.new(['image','.jpg'])
file.binmode
file.write decoded_file
return file
end