Search code examples
herokuamazon-s3shrine

Heroku, Shrine and Amazon S3: Blog post Images disappear after some time


I have a blog page I developed using rails 5.1. Everything works just fine, except that after I create a post in production and attach an image, the image stops showing after a while (say 30 minutes). I scouted around the internet looking for solutions and saw this which suggest the problem has to do with Heroku wiping the directory after every app restart. One solution offered is to host your images on a service like Amazon S3.

I have however set S3 up and the images are being sent to the bucket shown below: enter image description here

But still, the blog post images still disappear. I need help as I cannot figure out what I am missing. Here are the relevant codes:

shrine.rb:

require "shrine"
require "shrine/storage/s3"
s3_options = {
    access_key_id:      ENV['S3_KEY'],
    secret_access_key:  ENV['S3_SECRET'],
    region:             ENV['S3_REGION'],
    bucket:             ENV['S3_BUCKET'],
}

if Rails.env.development?
  require "shrine/storage/file_system"
  Shrine.storages = {
    cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), # temporary
    store: Shrine::Storage::FileSystem.new("public", prefix: "uploads/store")  # permanent
  }
elsif Rails.env.test?
  require 'shrine/storage/memory'
  Shrine.storages = {
    cache: Shrine::Storage::Memory.new,
    store: Shrine::Storage::Memory.new
  }
else
  require "shrine/storage/s3"

  Shrine.storages = {
    cache: Shrine::Storage::S3.new(prefix: "cache", **s3_options),
    store: Shrine::Storage::S3.new(prefix: "store", **s3_options)
  }
end
Shrine.plugin :activerecord # or :activerecord
Shrine.plugin :cached_attachment_data # for retaining the cached file across form redisplays

gemfile:

....................................
# A rich text editor for everyday writing
gem 'trix', '~> 0.11.1'
# a toolkit for file attachments in Ruby applications
gem 'shrine', '~> 2.11'
# Tag a single model on several contexts, such as skills, interests, and awards
gem 'acts-as-taggable-on', '~> 6.0'
# frameworks for multiple-provider authentication.
gem 'omniauth-facebook'
gem 'omniauth-github'
# Simple Rails app key configuration
gem "figaro"
..............................

I use Figaro gem to mask the env files. They are fine since the S3 bucket responds, plus I already have OmniAuth up and running on the blog.

Here is the error it shows on the chrome console for the image:

enter image description here

I really need help to get this blog up and running. Thank you for your time.


Solution

  • Shrine generates expiring S3 URLs by default, so it's possible that the generated URLs are somehow getting cached, and then the images become unavailable once the URL has expired.

    As a workaround, you can make S3 uploads public and generate public URLs instead. You can do that by telling the S3 storage to make uploads public (note that this will only affect new uploads, existing uploads will remain private so you'd have to make them public in another way), and to generate public URLs by default, by updating the initializer:

    # ...
    
    require "shrine/storage/s3"
    
    Shrine.storages = {
      cache: Shrine::Storage::S3.new(prefix: "cache", upload_options: { acl: "public-read" }, **s3_options),
      store: Shrine::Storage::S3.new(prefix: "store", upload_options: { acl: "public-read" }, **s3_options)
    }
    
    # ...
    
    Shrine.plugin :default_url_options, cache: { public: true }, store: { public: true }
    
    # ...