Shrine: Upload endpoint not working

Created on 17 Aug 2016  路  16Comments  路  Source: shrinerb/shrine

I'm trying to integrate this gem with fineuploader fron-end library to enhance the user experience (http://fineuploader.com/). The fineupload plugin require us to specify the URL where it should send uploads and server requests to. This endpoint can be an absolute path or a relative path. More information could be found here: http://docs.fineuploader.com/quickstart/02-setting_options.html

I've read shrine gem docs section: https://github.com/janko-m/shrine#direct-uploads and I've setup my endpoint in routes.rb as mount ImageUploader::UploadEndpoint, at: "/attachments/images" and I'm setting my endpoint in fineupload initializing function as:

    $("#fine-uploader-gallery").fineUploader({
        request: {
            endpoint: '/attachments/images/cache/upload'
        },
    });

But on network tab of chrome inspector, I can see that post request to this URL cause a status of 404. What could be the issue? Do I need to pass some parameters along with this endpoint? if so how to receive those parameters in my fineuploader function?

PS: I'm using this repository as base: https://github.com/erikdahlstrand/shrine-rails-example and I want to use _fineuploader_ instead of _jQuery file upload_ library.

Most helpful comment

I assume you meant this app: https://github.com/erikdahlstrand/shrine-rails-example 馃槈

Is the puts statement visible in the logs when you curl the endpoint now? I see that curl returned application/json Content-Type, so it seems that it is indeed hitting it.

Ok, I think I know now. If you load the direct_upload plugin with presign: true, it's going to include the only the presign route (/:storage/presign). I originally disabled the /:storage/upload route in that case for security reasons, but then I realized there are no security issues and it adds confusion, so I changed it in the latest version to always return both routes. Sorry for the confusion 馃槄

So you just need to update to 2.2.0, and it should work.

All 16 comments

Hmm, that's strange. The upload endpoint needs to receive a file parameter, but I'm sure that FineUploader sends it by default, because it's a convention. And if it doesn't, the response status wouldn't be "404 Not Found", but "400 Bad Request".

What happens if you try to manually curl it?

curl -i -X POST http://localhost:3000/attachments/images/cache/upload

Thanks for your reply. It is certainly a 404 status. I'm working on cloud IDE so you might want to check it yourself: https://shrine-imfaisal.c9users.io/

Running the curl command curl -i -X POST https://shrine-imfaisal.c9users.io/attachments/images/cache/upload gives following status:

HTTP/1.1 404 Not Found
content-type: application/json
content-length: 0
cache-control: no-cache
x-request-id: 5a4ba1aa-9bbf-4bac-bc78-20da71b3098b
x-runtime: 0.006039
server: WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
date: Wed, 17 Aug 2016 12:04:39 GMT
X-BACKEND: apps-proxy

Hmm, can you share your config/routes.rb? Could you also set a before filter on the endpoint, to see if the request is hitting the app at all?

ImageUploader::UploadEndpoint.plugin :hooks
ImageUploader::UploadEndpoint.before { puts "CALLED" }
mount ImageUploader::UploadEndpoint, at: "/attachments/images"

I've added your's mentioned code in my routes.rb, now this file looks like this:

Rails.application.routes.draw do
  root to: 'photos#index'

  patch "/album" => "photos#update"
  post "/album/photos" => "photos#create"


  ImageUploader::UploadEndpoint.plugin :hooks
  ImageUploader::UploadEndpoint.before { puts "CALLED" }
  mount ImageUploader::UploadEndpoint, at: "/attachments/images"

end

As mentioned earlier, all other code (model, view, controllers) are based on this demo app: https://github.com/erikdahlstrand/shrine-rails-example

I assume you meant this app: https://github.com/erikdahlstrand/shrine-rails-example 馃槈

Is the puts statement visible in the logs when you curl the endpoint now? I see that curl returned application/json Content-Type, so it seems that it is indeed hitting it.

Ok, I think I know now. If you load the direct_upload plugin with presign: true, it's going to include the only the presign route (/:storage/presign). I originally disabled the /:storage/upload route in that case for security reasons, but then I realized there are no security issues and it adds confusion, so I changed it in the latest version to always return both routes. Sorry for the confusion 馃槄

So you just need to update to 2.2.0, and it should work.

Yes, I meant to paste this link :)

So, I've updated the shrine gem to version 2.2.0 but it still not working. However, now it is returning 400 status instead of 404. Previous curl command now returns following status:

HTTP/1.1 400 Bad Request
content-type: application/json
content-length: 45
cache-control: no-cache
x-request-id: 62bf4930-a51d-475f-ba39-9a6df10d9d38
x-runtime: 0.006091
server: WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
date: Wed, 17 Aug 2016 13:41:14 GMT
X-BACKEND: apps-proxy

{"error":"Missing query parameter: \"file\""}

file param seems to be missing.

Maybe FineUploader isn't passing the file via file parameter (multipart upload), you can try to look into FineUploader docs. You can inspect what params are sent by putting binding.pry in the before filter, and inspecting request.params:

require "pry"
ImageUploader::UploadEndpoint.before { binding.pry }
pry >> request.params

This curl output is expected, because you have to pass the actual file.

(I closed the issue because this is now related to FineUploader.)

Ok, I'll look into it and thanks very much for your prompt support.

Well, for anybody who will be following this topic. The fineuploader library sends some parameters (to shrine upload endpoint) when some file is uploaded. These params names are qquuid, qqfilename, qqtotalfilesize, qqfile.

Now, since shrine gem is expecting the uploaded file in a param named file the request was responding with a 400 status before. So, we've to change the sent params name for qqfile parameter. For this the fineuploader provide some options, for detail: http://docs.fineuploader.com/api/options.html#request

So, after setting my fineuploader initializing code like following, now the request to upload endpoint is responding with a 200 status code and I can see the file uploaded in my aws S3 bucket in cache folder.

    $("#fine-uploader-gallery").fineUploader({
        request: {
            endpoint: '/attachments/images/cache/upload',
            inputName: "file",
        },
    });

However, fineuploader requires a specific kind of JSON response. Well, it's another issue, see: http://docs.fineuploader.com/endpoint_handlers/traditional.html#response

Fine Uploader, unfortunately, requires a JSON response to all upload requests due to support of IE9 and older, where the uploads are sent via form submits and the response status cannot be read client-side. Furthermore, returning a non-200 response in IE9 and older will cause problems as well (see the IE limitations section in the Fine Uploader docs for more info). v6.0 will likely contain an update to only require a JSON response for older browsers. See FineUploader/fine-uploader#1325 for more details.

Yes, that is unfortunately required due to the reasons detailed in my last post. If Fine Uploader only supported IE10+, none of this would be necessary. Luckily, in the future, the response requirements will be a bit more flexible.

@rnicholus So, I hope there is any method to modify the response to include the success property on server end untill the v6.0 is release of fineuploader.

I can't answer that question. @janko-m is probably the best person to ask. Note that if you do plan on supporting IE9 or older, you will need the JSON success property no matter what.

Yeah, I've opened up a ticket, let see what's possible. Thanks.

@nickooolas This is the issue that @imfaisalkh opened afterwards, and here is the middleware that you need to use in UploadEndpoint to add the success field.

Note that I will make this much easier in the future, as I plan to split out direct_upload plugin into upload_endpoint and presign_endpoint, so they will be able to have options for modifying the response (so that you don't have to do all this boilerplate like updating Content-Length header). But for now this middleware is the best way IMO.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

brunowego picture brunowego  路  4Comments

waclock picture waclock  路  8Comments

tayagi-aim picture tayagi-aim  路  5Comments

brunowego picture brunowego  路  3Comments

jakehockey10 picture jakehockey10  路  6Comments