简体   繁体   English

S3上的Rails + 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 . 示例:Jon Smith上传了他的头像,文件名为4321431-small.jpg On download, I'd like to rename the file to jon_smith__headshot.jpg . 在下载时,我想将文件重命名为jon_smith__headshot.jpg

View: <%= url_for user.headshot_file %> 查看: <%= url_for user.headshot_file %>

This url_for downloads the file from Amazon S3, but with the original filename. url_for从Amazon S3下载文件,但使用原始文件名。

What are my options here? 我有什么选择?

The built-in controller serves blobs with their stored filenames. 内置控制器为blob提供存储的文件名。 You can implement a custom controller that serves them with a different filename: 您可以使用不同的文件名实现自定义控制器:

class HeadshotsController < ApplicationController
  before_action :set_user

  def show
    redirect_to @user.headshot.service_url(filename: filename)
  end

  private
    def set_user
      @user = User.find(params[:user_id])
    end

    def filename
      ActiveStorage::Filename.new("#{user.name.parameterize(separator: "_")}__headshot#{user.headshot.filename.extension_with_delimiter}")
    end
end

Starting with 5.2.0 RC2, you won't need to pass an ActiveStorage::Filename ; 从5.2.0 RC2开始,您不需要传递ActiveStorage::Filename ; you can pass a String filename instead. 你可以传递一个String文件名。

The approach of @GuilPejon will work. @GuilPejon的方法将起作用。 The problem with directly calling the service_url is: 直接调用service_url的问题是:

  1. It is short-lived (not recommended by rails team) 它是短暂的(不是铁路团队推荐)
  2. It will not work if the service is disk in development mode. 如果服务是处于开发模式的disk ,它将无法工作。

The reason it does not work for disk service is that disk service requires ActiveStorage::Current.host to be present for generating the URL. 它不适用于磁盘服务的原因是磁盘服务需要ActiveStorage::Current.host才能生成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. 并且在app/controllers/active_storage/base_controller.rb设置了ActiveStorage::Current.host ,因此在调用service_url时它将丢失。

ActiveStorage as of now gives one more way of accessing the URL of the attachments: ActiveStorage到目前为止提供了另一种访问附件URL的方法:

  1. Using rails_blob_(url|path) (recommended way) 使用rails_blob_(url|path) (推荐方式)

But if you use this, you can only provide content-disposition and not the filename. 但是如果你使用它,你只能提供content-disposition而不是文件名。

If you see the config/routes.rb in the `ActiveStorage repo you will find the below code. 如果你在`ActiveStorage repo中看到config/routes.rb ,你会发现下面的代码。

    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: 当你研究blobs_controller你会发现以下代码:

    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. 所以很明显,在rails_blob_(url|path)你只能传递disposition而已。

I know this was already answered, but I would like to add a second way of doing this. 我知道这已经回答了,但我想补充第二种做法。 You could update your file name when the user object is saved. 保存用户对象时,可以更新文件名。 Using OP's example of the user model and the headshot_file field, this is how you could solve this: 使用OP的user模型示例和headshot_file字段,您可以通过以下方式解决此问题:

# app/models/user.rb

after_save :set_filename

def set_filename
  file.blob.update(filename: "ANYTHING_YOU_WANT.#{file.filename.extension}") if file.attached?
end

I haven't played with ActiveStorage yet, so this is kind of a shot in the dark. 我还没有玩过ActiveStorage,所以这是一个黑暗中的镜头。

Looking at the ActiveStorage source for the S3 service, it looks like you can specify the filename and disposition for the upload. 查看S3服务的ActiveStorage ,看起来您可以指定上载的文件名和处置方式。 From the guides it seems that you can use rails_blob_path to access the raw URL of the upload and pass these parameters. 指南中可以看出,您可以使用rails_blob_path访问上载的原始URL并传递这些参数。 Therefor you might try: 因此你可以尝试:

rails_blob_url(user.headshot_file, filename: "jon_smith__headshot.jpg"`enter code here`)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM