S3保存旧网址,更改回形针配置,将新网址设置为旧网址

Posted

技术标签:

【中文标题】S3保存旧网址,更改回形针配置,将新网址设置为旧网址【英文标题】:S3 save old url, change paperclip config, set new url as old 【发布时间】:2021-11-13 23:02:59 【问题描述】:

所以事情是这样的:目前我们的文件,当用户下载它们时,名称类似于897123uiojdkashdu182uiej.pdf。我需要将其更改为file-name.pdf. 从逻辑上讲,我去更改 paperclip.rb 配置:

Paperclip::Attachment.default_options.update(
                                               path: '/:hash.:extension',
                                               hash_secret: Rails.application.secrets.secret_key_base
                                             )

到这里:

Paperclip::Attachment.default_options.update(
                                               path: "/attachment/#SecureRandom.urlsafe_base64(64)/:filename",
                                               hash_secret: Rails.application.secrets.secret_key_base
                                             )

效果很好,文件名很棒。但是,由于路径的更改,旧文件现在无法访问。所以我想出了以下决定 首先我做了一个 rake 任务,它将旧路径存储在数据库中:

namespace :paperclip do
  desc "Set old urls for attachments"
  task :update_old_urls => :environment do

    Asset.find_each do |asset|
      if asset.attachment
        attachment_url = asset.attachment.try!(:url)
        file_url = "https:#attachment_url"

        puts "Set old url asset attachment #asset.id - #file_url"
        asset.update(old_url: file_url)
      else
        puts "No attachment found in asset #asset.id"
      end
    end
  end
end

现在asset.old_url 存储文件的当前网址。然后我去更改配置,使文件无法访问。 现在是时候执行新的 rake 任务了:

require 'uri'
require 'open-uri'

namespace :paperclip do
  desc "Recreate attachments and save them to new destination"
  task :move_attachments => :environment do

    Asset.find_each do |asset|
      unless asset.old_url.blank?
        url = asset.old_url
        filename = File.basename(asset.attachment.path)
        file = File.new("#Rails.root/tmp/#filename", "wb")
        file.write(open(url).read)

        if File.exists? file
          puts "Re-saving asset attachment #asset.id - #filename"
          asset.attachment = file
          asset.save
          # if there are multiple styles, you want to recreate them :
          asset.attachment.reprocess!
          file.close
        else
          puts "Missing file attachment #asset.id - #filename"
        end
        File.delete(file)
      end
    end
  end
end

但我的计划根本没有奏效,我无法访问这些文件,而且asset.url 仍然不等于asset.old_url

非常感谢帮助!

【问题讨论】:

【参考方案1】:

使用 S3,您可以将“保存时的文件名”设置为标题。具体来说,用户将获得一个 url https://foo.bar.com/mangled/path/some/weird/hash/whatever?options,当浏览器提供保存时,您可以控制文件名(而不是 url)。

这个技巧依赖于浏览器从响应中读取Content-Disposition 标头,如果它读取Content-Disposition: attachment; filename="filename.jpg",它将保存(或要求用户另存为)filename.jpg,独立于原始 URL。

您可以通过向 URL 添加一个参数或在文件上设置元数据来强制 S3 添加此标头。

前者可以通过将其传递给url 方法来完成:

has_attached_file :attachment, 
                  s3_url_options: ->(instance)  
                    response_content_disposition: "attachment; filename=\"#instance.filename\""
                  

查看https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/storage/s3.rb#L221-L225获取相关源代码。

后者可以通过回形针批量完成(您还应该将其配置为在新上传时执行此操作)。还要等很久!!

Asset.find_each do |asset|
  next unless asset.attachment
  
  s3_object = asset.attachment.s3_object
  s3_object.copy_to(
    s3_object,
    metadata_directive: 'REPLACE',
    content_disposition: "attachment; filename=\"#asset.filename\")"
  )
end
# for new uploads
has_attached_file :attachment, 
                  s3_headers: ->(att) 
                    content_disposition: "attachment; filename=\"#att.model.filename\""
                  

【讨论】:

以上是关于S3保存旧网址,更改回形针配置,将新网址设置为旧网址的主要内容,如果未能解决你的问题,请参考以下文章

使用旧 Laravel 5.4 附加新网址

如何在 Amazon S3 中自定义 Rails 5.2 ActiveStorage 附件的路径?

Rails - 为 S3 迁移重新保存所有模型

仅将处理后的图像保存在回形针中

状态码301 302

无法使用回形针导轨上传到S3 5.配置选项无效:存储桶