I have just created a private bucket on s3, to contain user profile pictures. With a public bucket, all of the images are properly cached (previous paperclip config with same settings).
I have the following shrine initializer:
s3_options = {
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
region: ENV['AWS_REGION'],
bucket: ENV['S3_BUCKET_NAME']
}
Shrine.storages = {
cache: Shrine::Storage::FileSystem.new('tmp', prefix: 'uploads/cache'),
store: Shrine::Storage::S3.new(**s3_options)
}
Shrine.plugin :activerecord
Shrine.plugin :logging
Shrine.plugin :determine_mime_type
Shrine.plugin :cached_attachment_data
Shrine.plugin :restore_cached_data
Shrine.plugin :delete_promoted
Shrine.plugin :delete_raw
Shrine.plugin :remove_invalid
And the following uploader:
class AvatarUploader < Shrine
plugin :pretty_location
plugin :processing
plugin :upload_options, store: {
acl: 'private',
cache_control: "max-age=604800",
}
end
The CacheControl gets properly set to 1 week on the s3 object and the same is visible in the response. I have noticed that on each request the signed url differs regarding the X-Amz-Signature hash, which most likely causes the cache-miss (Etag is the same for each request). I presume this is the reason it isn't working, but I have no clue on how to make the X-Amz-Signature the same while the object isn't expired.
The ruby S3 SDK will generate a new signature every time you generate a signed URL, this is by design.
You should either
a) stick with public, non-signed requests
b) cache the signed url, so that a new signature won't be generated on every call, but expires before the signature expires
Something like this might do the trick
def url
Rails.cache.fetch("url", self, expires_in: 6.days) do
super(public: false, expires_in: 1.week)
end
end