【问题标题】:Rails + ActiveStorage on S3: Set filename on download?S3上的Rails + ActiveStorage:在下载时设置文件名?
【发布时间】:2018-02-07 20:30:37
【问题描述】:

有没有办法在下载时更改/设置文件名?

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

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

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

我有什么选择?

【问题讨论】:

  • 下载代码是什么?
  • url_for user.headshot_file 如描述中所述。 url_for 自动提供下载 URL。
  • 你试过<%= url_for user.headshot_file, filename: "jon_smith__headshot.jpg" %>
  • url_for 只接受一个参数。
  • 必须是url_for吗?您可以使用下载图像方法编写link_to。或者,您可以在将其保存到 S3 之前重命名文件名。

标签: ruby-on-rails amazon-s3 filenames rails-activestorage


【解决方案1】:

内置控制器为 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 文件名。

【讨论】:

  • 谢谢,这种方法有效,我接受它作为答案。对我来说缺少的部分是使用model.attachment_field.service_url filename: filename,其中filenameActiveStorage::Filename。话虽如此,我可能会实现一个更简单的解决方案,它不需要为每个附件类型单独的控制器和路由。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

    它不适用于磁盘服务的原因是磁盘服务需要存在ActiveStorage::Current.host 才能生成 URL。而ActiveStorage::Current.host 被设置在app/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,仅此而已。

    【讨论】:

    • service_url 采用 expires_in 选项 - 我猜 - 可用于操纵 url 的生命周期。
    【解决方案4】:

    我还没有玩过 ActiveStorage,所以这有点像在黑暗中拍摄。

    查看 S3 服务的 ActiveStorage source,看起来您可以为上传指定文件名和处置。从guides 看来,您可以使用rails_blob_path 访问上传的原始URL 并传递这些参数。因此,您可以尝试:

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

    【讨论】:

    • 不幸的是,这并不像宣传的那样有效。它会生成http://localhost:3000/rails/active_storage/blobs/ey...c/new_filename.png.old_filename.png" 格式的链接,下载时会将文件保存为old_filename.png。我认为现在重命名 blob 中的文件名是我最好的选择。
    • Active Storage 不使用下载 URL 中的文件名。它可以容纳不尊重 Content-Disposition 标头中文件名的旧浏览器。
    猜你喜欢
    • 2019-02-18
    • 2023-03-30
    • 1970-01-01
    • 2019-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    相关资源
    最近更新 更多