-
-
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/