I recently took advantage of Rails 6.1's support for using multiple different Active Storage services in one app, on an association-by-association basis:
class MyClass < ApplicationRecord
has_many_attached :cool_documents
has_many_attached :even_cooler_documents, service: :my_new_service
end
with a storage.yml
that looks something like this:
local:
service: Disk
root: <%= Rails.root.join("storage") %>
my_first_service:
service: S3
access_key_id: <%= ENV['AWS_ACCESS_KEY'] %>
secret_access_key: <%= ENV['AWS_SECRET_KEY'] %>
region: us-east-1
bucket: <%= ENV['MY_FIRST_BUCKET'] %>
my_new_service:
service: S3
access_key_id: <%= ENV['AWS_ACCESS_KEY'] %>
secret_access_key: <%= ENV['AWS_SECRET_KEY'] %>
region: us-east-1
bucket: <%= ENV['MY_NEW_BUCKET'] %>
However, we have a developer quality-of-life problem -- we really like having a fallback mechanism for local dev that says "Do you have the ENV variables needed for the AWS storage config? If so, let's use it. If not, let's use local storage." This manifested in some code in our development.rb
config file like this:
config.active_storage.service = if ENV["AWS_ACCESS_KEY"].present? && ENV["AWS_SECRET_KEY"].present?
:my_first_service
else
:local
end
This worked GREAT when there was just one relevant Active Storage service for the app -- the default. However, the config for my_new_service
breaks this -- you've gotta have the right ENV config present to configure my_new_service
, or the app throws errors when it cannot configure the service. Furthermore, so far I cannot figure out how to make this work gracefully and to "hot swap" config the way I'd like to. Does anybody out there have any ideas on how we could configure this?
Your storage.yml
is an erb file so you could just manage it in there. It's not great but should work.
local:
service: Disk
root: <%= Rails.root.join("storage") %>
my_first_service:
service: S3
access_key_id: <%= ENV['AWS_ACCESS_KEY'] %>
secret_access_key: <%= ENV['AWS_SECRET_KEY'] %>
region: us-east-1
bucket: <%= ENV['MY_FIRST_BUCKET'] %>
my_new_service_prod:
service: S3
access_key_id: <%= ENV['AWS_ACCESS_KEY'] %>
secret_access_key: <%= ENV['AWS_SECRET_KEY'] %>
region: us-east-1
bucket: <%= ENV['MY_NEW_BUCKET'] %>
<% if Rails.env.production? %>
my_new_service:
service: my_new_service_prod
<% else %>
my_new_service:
service: local
<% end %>
In production my_new_service
will now point to local, otherwise to local
.