I am having an issue with Active Storage. When I upload to Amazon S3, instead of saving the file inside the bucket with the original name like myfile.zip
it is saving it as the key
which is associated with that file. So in Cyberduck I am seeing something like this: 5YE1aJQuFYyWNr6BSHxhQ48t
. Without any file extension.
I am not sure if there is some setting in Rails 5 or whether it is within Amazon S3 but I have spent hours Googling around to figure out why this is happening.
Any pointers would be really appreciated!
Best regards,
Andrew
This is by design, from ActiveStorage. The file is stored by it's key and without extension on S3, but when the URL is generated by ActiveStorage, the disposition and filename are set.
def url(key, expires_in:, filename:, disposition:, content_type:)
instrument :url, key: key do |payload|
generated_url = object_for(key).presigned_url :get, expires_in: expires_in.to_i,
response_content_disposition: content_disposition_with(type: disposition, filename: filename),
response_content_type: content_type
payload[:url] = generated_url
generated_url
end
end
This is probably done to avoid filename escaping issues that you'd run into otherwise.
You can read more about the Content-Disposition
headers here.
You can still reference the name with filename accessor.
class User < ApplicationRecord
has_one_attached :photo
...
end
filename = User.first.photo.filename
In order to have a custom filename on S3, you should update both blob.key
and the name on S3.
Active storage uploads images on S3 using blob.key
as remote image path and name.
For my usage, I only changed the name for 'images variants' with a Monkey Patch that allows to generate a key
terminating by the filename
:
config/initializers/active_storate_variant.rb
:
ActiveStorage::Variant.class_eval do
def key
"variants/#{blob.key}/#{Digest::SHA256.hexdigest(variation.key)}/#{filename}"
end
end
So when I need the public url for an image variant, I just call image.url('400x400')
This is how my Image model is customized :
class Image < ApplicationRecord
belongs_to :imageable, polymorphic: true
has_one_attached :picture
SIZES = { '400x400' => '400x400' }
def url(size)
return "https://placehold.it/#{size}" unless picture.attached?
'https://my_s3_subdomain.amazonaws.com/' +
picture.variant(resize: SIZES[size]).processed.key
end
...
end
If someone has a better way to do that, I would be happy to see it :)