4

This is about a Rails app on Heroku that runs behind CloudFront and serves ActiveStorage images from the Bucketeer add-on.

Cache config in both the Rails app itself and CloudFront are right on target for css, js, and even key, important requests (like search results, 3rd party info fetched from APIs, etc).

What I can't figure out how to cache are the images that come from the Bucketeer add-on.

Right now the images seem to come from the Bucketeer bucket every time. They show up with no Cache TTL.

I'd like for them to be cached for up to a year both at the CloudFront level and the visitor's browser level.

Is this possible?

It seems like the Bucketeer add-on itself gives us no control over how the bucket and/or the service handles caching.

Where can I force these files to show up with caching instructions?

vivipoit
  • 160
  • 2
  • 11

2 Answers2

6

Thanks for sharing your findings here

Additionally, I found that S3Service accepts upload options https://github.com/rails/rails/blob/6-0-stable/activestorage/lib/active_storage/service/s3_service.rb#L12

So you can add the following code to your storage.yml

s3:
  service: S3
  access_key_id: ID
  secret_access_key: KEY
  region: REGION
  bucket: BUCKET
  upload:
    cache_control: 'public, max-age=31536000'

For a full list of available options refer to AWS SDK

Alex Suslyakov
  • 2,042
  • 2
  • 14
  • 15
  • This did not work for me. My uploads are through `rails_admin`. Could that be related? – vivipoit Nov 24 '19 at 06:35
  • @vivipoit You should check which ActiveStorage service your uploads use underneath. In the `storage.yml` there should be a line `service: S3` (see updated answer for full content) If it's not S3 you should check what options the desired ActiveStorage service accepts. List of services can be found here https://github.com/rails/rails/tree/6-0-stable/activestorage/lib/active_storage/service Gems may provide custom services under the same namespace – Alex Suslyakov Nov 25 '19 at 13:37
  • Even though I said it hadn't worked, I left it there and it DOES work. I guess I must have checked the wrong files. Sorry about that. This was helpful and has been great. – vivipoit Apr 29 '20 at 12:08
  • I'm now looking forward to the possibility of serving Active Storage files through CDN, which would be awesome on infinite levels and seems to be ready for Rails 6.1!! :-) So many performance problems will go away when that becomes a reality. :-) – vivipoit Apr 29 '20 at 12:10
2

After a lot of searching, I learned that Bucketeer does give bucket control. You just have to use AWS CLI.

Here is the link to AWS docs on CLI: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html

And here is the link where Bucketeer tells you how to get started with that on their service: https://devcenter.heroku.com/articles/bucketeer#using-with-the-aws-cli

This means you can install AWS CLI, do the aws configure with the credentials Bucketeer provides, and then go on to change cache-control in the bucket directly.

AWS does not seem to have a feature for setting cache-control defaults for an entire bucket or folder, so you actually do it to each object.

In my case, all of my files/objects in the bucket are images that I display on the website and need to cache, so it's safe to run a command that does it all at once.

Such a command can be found in this answer: How to set expires headers to all images in a bucket in Amazon S3

For me, it looked like this: aws s3 cp s3://my-bucket-name s3://my-bucket-name --recursive --acl public-read --metadata-directive REPLACE --cache-control max-age=43200000

The command basically copies the entire bucket onto itself while adding the cache-control max-age=43200000 header to each object in the process.

This works for all existing files, but will not change anything for future changes or additions. You'd have to run this again every so often to catch new stuff and/or write code to set your object headers when saving the object to the bucket. Apparently there are people that have had luck with this. Not me.

Thankfully, I found this post: https://www.neontsunami.com/posts/caching-variants-with-activestorage

This monkey-patch basically changes ActiveStorage::RepresentationsController#show to use Rails action caching for variants. Take a look. If you're having similar issues, it's worth the read.

There are drawbacks. For my case, they were not a problem, so this is the solution I went with.

vivipoit
  • 160
  • 2
  • 11