Shrine with public and private derivatives on S3

I read the docs and want to make some derivatives private and some other public, depending where they are displayed in the website.

This is what I did:

plugin :upload_options, store: -> (io, derivative: nil, **) do
		if derivative == :tiny or derivative == :small
			{ acl: "public-read" } 
		else
			{ acl: "private" }
		end
	end
  plugin :url_options, store: { expires_in: 3600 }

I made some tests in dev env, and seems to work, but to be sure:

if derivative == :tiny or derivative == :small
    			{ acl: "public-read" } 

=> it will be private by default EVEN IF the { acl: “public-read” } is set, but public with a url(“public:true”) link. My tests shows this behavior…

{ acl: "private" }

=> can only be be private (public:true gives a 403 Forbidden url)

Is-it the good way to manage that ?

It’s not clear to me from the description what is the exact problem, and what exact code produces what unexpected behaviour.

Files need to be uploaded with { acl: "public-read" } in order to be accessible by public URLs.

Hi Janko,

In fact, I just want to be sure that the normal behavior when we display a link with this setting is that the URL is private (signed) by default. So, I need public:true in the link, even if it was uploaded with`{ acl: “public-read” }.

I just want to be sure that the normal behavior when we display a link with this setting is that the URL is private (signed) by default.

Yes, S3 storage URLs are already private (signed) by default.

So, I need public:true in the link, even if it was uploaded with`{ acl: “public-read” }.

This won’t work for files with private ACL, as for those using a public URL will result in 403, as you’ve seen. That’s what private vs public ACL means, for private (default) ACL public (unsigned) URLs don’t work.

You probably want to generate public URLs only for files uploaded with public ACL. The problem is that with the url_options plugin, you don’t have access to the current derivative inside a dynamic block, nor the attacher/record.

As a workaround, I would recommend saving the derivative name in the metadata:

class MyUploader < Shrine
  plugin :add_metadata
  add_metadata :derivative do |io, derivative: nil, **|
    derivative&.to_s
  end
end

Then with the url_options plugin you can add public: true only for those derivatives:

plugin :url_options, store: -> (file, options) do
  if %w[tiny small].include?(file.derivative)
    { public: true }
  else
    { expires_in: 3600 }
  end
end

I haven’t tested this, but I think it should work. I might update the derivatives plugin to add this metadata automatically.

Thanks for your suggestion adding the derivative in the metadata. It’s a great idea.
However, for my needs, I think I don’t need that “level of details”:

True. But only in some “places” on my website, not on the app search engine for example. So working with the upload_options(acl: "public-read") and public:true is just what I need.

Thanks for all your help and suggestions Janko.
Have a good week-end. Alexandre