ruby-on-railsamazon-s3ruby-on-rails-5amazon-cloudfrontshrine

Shrine - Derivation Endpoint and full path URLs with Cloudfront


I'm using Shrine with Rails to upload my images directly to S3, they are then served using Cloudfront.

My setup is working great, but I'm stuck trying to answer 2 issues:

1) User uploads a new Image via Uppy. They click "Create Image Page" which creates a new "page" object. The user is taken to a blank page, while the Image derivative is being created in a background process using Sidekiq. How can we have the image "pop-in" via JS once the derivative is successfully created and promoted to /store? Is there a callback we can pick up on, or is it possible to keep trying to find the derivative via JS until it exists?

2) Using the Derivatives Endpoint plugin, all of the image URLs are relative. Is there a way to serve this as absolute URLs from Cloudfront/Custom Domain? Here's an example using Rails:

Ruby code:

<%= image_tag(image.image_file.derivation_url(:banner, 800, 300)) %>

Resulting HTML:

<img src="/derivations/images/banner/800/300/...">

How can I instead serve this resulting URL:

<img src="http://abc123.cloudfront.net/derivations/images/banner/800/300/...">

Was this intentional to prevent DoS? Thanks.

Adding the host option to "derivation_endpoint" causes the following error returned as XML:

<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>...</RequestId>
    <HostId>...</HostId>
</Error>

Could this be my Cloudfront access settings? Maybe CORS.

Here is my derivation_endpoint setup in image_uploader.rb

plugin :derivation_endpoint, host: "http://abc123.cloudfront.net", prefix: "derivations", secret_key: ..., upload: true

routes.rb

mount Shrine.presign_endpoint(:cache) => "s3/params"
mount PhotoUploader.derivation_endpoint => "derivations/images"

config/initializers/Shrine.rb

Shrine.plugin :url_options, store: { host: "http://abc123.cloudfront.net" }

Solution

    1. Since the background job will update the record with derivatives, the easiest would be to poll the "show" route of the record (i.e. GET /images/:id) on the client side. In this case the route could have an alternative JSON response via respond_to.

      Alternatively, you could send a message from the background job to the client once processing is finished, via WebSockets or something like message_bus.

    2. You can configure the :host option for the derivation_endpoint plugin:

      Shrine.plugin :derivation_endpoint, host: "https://cloudfront.net"