Skip to content

Instantly share code, notes, and snippets.

@longlostnick
Created June 17, 2014 18:20
Show Gist options
  • Star 51 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save longlostnick/9291167a0a4367bb55a2 to your computer and use it in GitHub Desktop.
Save longlostnick/9291167a0a4367bb55a2 to your computer and use it in GitHub Desktop.
Rails JSON file upload with carrierwave (from base64 string)
class Api::UploadsController < ApiController
def create
@upload = Upload.new(upload_params)
ensure
clean_tempfile
end
private
def upload_params
the_params = params.require(:upload).permit(:file)
the_params[:file] = parse_image_data(the_params[:file]) if the_params[:file]
the_params
end
def parse_image_data(base64_image)
filename = "upload-image"
in_content_type, encoding, string = base64_image.split(/[:;,]/)[1..3]
@tempfile = Tempfile.new(filename)
@tempfile.binmode
@tempfile.write Base64.decode64(string)
@tempfile.rewind
# for security we want the actual content type, not just what was passed in
content_type = `file --mime -b #{@tempfile.path}`.split(";")[0]
# we will also add the extension ourselves based on the above
# if it's not gif/jpeg/png, it will fail the validation in the upload model
extension = content_type.match(/gif|jpeg|png/).to_s
filename += ".#{extension}" if extension
ActionDispatch::Http::UploadedFile.new({
tempfile: @tempfile,
content_type: content_type,
filename: filename
})
end
def clean_tempfile
if @tempfile
@tempfile.close
@tempfile.unlink
end
end
end
@longlostnick
Copy link
Author

@longlostnick
Copy link
Author

This takes the place of what Rack normally does automatically for file uploads. We explicitly create our own instance of ActionDispatch::Http::UploadedFile from the base64 string which is what carrierwave expects.

@melcher
Copy link

melcher commented Feb 11, 2015

This idea was turned into a gem as well https://github.com/lebedev-yury/carrierwave-base64

@Mohakjuneja
Copy link

@ifightcrime In what format should we send the file data in the JSON?
For instance my JSON looks like-
{ "content": { "asset": "data:application/pdf;base64,(L2hvbWUvbW9qby9Eb3dubG9hZHMvYm9va2UucGRm)" } }

Is this correct?

@Mohakjuneja
Copy link

Hey @ifightcrime I was able to make it work by changing line 23 of code
@tempfile.write Base64.decode64(string) to this
@tempfile.write File.open(Base64.decode64(string)).read
Is this approach correct?

@txssseal
Copy link

txssseal commented Apr 7, 2016

👍

@adamcrown
Copy link

FYI, ActionDispatch::Http::UploadedFile expects type not content_type.

ActionDispatch::Http::UploadedFile.new({
  tempfile: @tempfile,
  type: content_type,
  filename: filename
})

Seems weird, I know. But it is what it is.

Thanks, by the way. This was really helpful.

@trantorLiu
Copy link

@adamcrown Thank you for the useful info :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment