-
-
Save longlostnick/9291167a0a4367bb55a2 to your computer and use it in GitHub Desktop.
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 |
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.
This idea was turned into a gem as well https://github.com/lebedev-yury/carrierwave-base64
@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?
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?
👍
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.
@adamcrown Thank you for the useful info :)
original source: http://blag.7tonlnu.pl/blog/2014/01/22/uploading-images-to-a-rails-app-via-json-api/