Search code examples
ruby-on-railsamazon-s3filenamesrails-activestorage

Rails + ActiveStorage on S3: Set filename on download?


Is there a way to change/set the filename on download?

Example: Jon Smith uploaded his headshot, and the filename is 4321431-small.jpg. On download, I'd like to rename the file to jon_smith__headshot.jpg.

View: <%= url_for user.headshot_file %>

This url_for downloads the file from Amazon S3, but with the original filename.

What are my options here?


Solution

  • The approach of @GuilPejon will work. The problem with directly calling the service_url is:

    1. It is short-lived (not recommended by rails team)
    2. It will not work if the service is disk in development mode.

    The reason it does not work for disk service is that disk service requires ActiveStorage::Current.host to be present for generating the URL. And ActiveStorage::Current.host gets set in app/controllers/active_storage/base_controller.rb, so it will be missing when service_url gets called.

    ActiveStorage as of now gives one more way of accessing the URL of the attachments:

    1. Using rails_blob_(url|path) (recommended way)

    But if you use this, you can only provide content-disposition and not the filename.

    If you see the config/routes.rb in the `ActiveStorage repo you will find the below code.

        get "/rails/active_storage/blobs/:signed_id/*filename" => "active_storage/blobs#show", as: :rails_service_blob
    
        direct :rails_blob do |blob, options|
            route_for(:rails_service_blob, blob.signed_id, blob.filename, options)
        end
    
    

    and when you look into blobs_controller you will find the below code:

        def show
            expires_in ActiveStorage::Blob.service.url_expires_in
            redirect_to @blob.service_url(disposition: params[:disposition])
        end
    

    So it is clear that in rails_blob_(url|path) you can only pass disposition and nothing more.