Currently, ActionText attachments use the default storage service.
If we want one ActionText has_rich_text on a model to use a public service, the whole app needs to be public first, rather than private first, which would be my preference.
Allowing a per case configuration as is possible with native-to-model attachables would allow the developer to choose their preference, and importantly allow that data-privacy-first approach.
I guess it should fall back to the default configured service if none is specified.
Thank you @simmerz. I came back to this topic after discovering that our Action Text embedded images stopped working, however images attached directly with Active Storage still work. One difference is that the former use the default service which is a private S3 storage, whereas the latter service is a public S3 storage. We recently rotated the credentials to access AWS, I wonder if it may be the cause of images breaking? I also note that if the secret_key_base changes, attachments (either direct or embedded in Action Text) will also break.
All of these reasons make me uncomfortable using a non-public storage for Action Text embeds, and before proceeding to fixing them I would like the embedded images to use the public storage service instead of the default. I’ll see if we can monkey-patch our app to do so.
Then in a second step we’d need to carefully investigate why the images broke and find better strategies for credential rotation, and document these.
credentials for accessing AWS shouldn’t matter at all. We’ve successfully transitioned between S3 and DigitalOcean Spaces (S3 compatible) which has meant different credentials. You’re right though that if your secret key changes then your attachments will no longer work as it provides the hashing key for the attachment.
Was the rotation the only change or did you also change the secret key base and perhaps did you change the configuration of the buckets in storage.yml which could also have an impact?
We’ve successfully transitioned between S3 and DigitalOcean Spaces (S3 compatible)
Do you also have embedded Action Text images using a private S3 service (not public: true)?
To the best of my knowledge, the secret key base hadn’t been changed, nor storage.yml. This is according to the git log and the Heroku activity history. However I discovered that the secret key base was ending with a spurious newline character, I wonder if this started to be handled differently when updating Rails (e.g. some trim added somewhere). Considering images are broken anyway, I will probably rotate the secret key base (and remove that trailing newline) and then repair the situation.
Here is one temporary solution that seems to work to ensure ActionText::RichText embeds are stored in a specific service:
EDIT: after a quick check the code below doesn’t seem to change the service at all, merely changing the service_name saved in the DB.
# config/initializers/action_text.rb
module ActionText
Rails.application.reloader.to_prepare do
unless RichText.included_modules.include?(RichTextMonkeyPatch)
RichText.include(RichTextMonkeyPatch)
end
end
end
# lib/action_text/rich_text_monkey_patch.rb
module ActionText
module RichTextMonkeyPatch
extend ActiveSupport::Concern
included do
before_save do
embeds&.each { |e| e.service_name = :public }
end
end
end
end
The previous comment didn’t work, but this hack does seem to work (use a specific service for all direct-uploaded attachments):
# config/initializers/active_storage.rb
Rails.application.reloader.to_prepare do
ActiveStorage::DirectUploadsController.class_eval do
def create # override previous definition
blob = ActiveStorage::Blob.create_before_direct_upload!(**blob_args.merge(service_name: "public"))
render json: direct_upload_json(blob)
end
end
end