Rails + S3 上的 ActiveStorage:在下载时设置文件名?

Rails + ActiveStorage on S3: Set filename on download?

有没有办法 change/set 下载文件名?

示例:Jon Smith 上传了他的头像,文件名为 4321431-small.jpg。下载时,我想将文件重命名为 jon_smith__headshot.jpg.

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

url_for 从 Amazon S3 下载文件,但使用原始文件名。

我有哪些选择?

我还没有玩过 ActiveStorage,所以这是盲目尝试。

查看 ActiveStorage source for the S3 service, it looks like you can specify the filename and disposition for the upload. From the guides,您似乎可以使用 rails_blob_path 访问上传的原始 URL 并传递这些参数。因此你可以试试:

rails_blob_url(user.headshot_file, filename: "jon_smith__headshot.jpg")

内置控制器为 blob 提供存储的文件名。您可以实现一个自定义控制器,为它们提供不同的文件名:

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

从 5.2.0 RC2 开始,您将不再需要传递 ActiveStorage::Filename;您可以改为传递 String 文件名。

我知道这个问题已经得到解答,但我想添加第二种方法。您可以在保存用户对象时更新文件名。使用 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

@GuilPejon 的方法会奏效。直接调用 service_url 的问题是:

  1. 它是短暂的(rails 团队不推荐)
  2. 如果服务处于disk开发模式,则无法使用。

它对磁盘服务不起作用的原因是磁盘服务需要 ActiveStorage::Current.host 才能生成 URL。 ActiveStorage::Current.hostapp/controllers/active_storage/base_controller.rb 中设置,因此在调用 service_url 时它将丢失。

ActiveStorage 目前提供了另一种访问附件 URL 的方法:

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

但是如果你使用这个,你只能提供content-disposition而不能提供文件名。

如果您在 `ActiveStorage 存储库中看到 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

当您查看 blobs_controller 时,您会发现以下代码:

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

所以很明显,在rails_blob_(url|path)中你只能通过disposition,仅此而已。