如何在更新文件时在 carrierwave 中保持相同的文件名(rails)

How to keep the same filename in carrierwave when updating a file (in rails)

当使用载波更新图像时,我将其设置为使用模型 ID 和原始文件名

def filename
 "#{model.id}-#{original_filename}" if original_filename.present?
end

之所以这样,是因为这是我在设置载波时发现的默认方式。最近我意识到,如果您更新图像,图像的 link 会损坏,因为文件名已更新为使用较新的文件名。因此,如果页面 link 编辑为旧图像,则它不会更新为新图像,而是变成损坏的图像 link。

我希望它在更新图像时保留旧文件名,但无法在文档和谷歌搜索中找到如何做到这一点

编辑

我没有添加很多 'use case' 因为我没想到问题这么复杂。

基本上在网站上有 items 个分配给了 images 个。我确实看到了关于 not using only model.id 的评论,@struthersneil 澄清了为什么会有该评论。考虑到项目的 images 记录是在创建项目时创建的,在添加图像时它们永远不会是新的(因为它只是更新已经存在的记录)。因此,我会说我最好的选择是只使用 model.id 作为文件名。

我的另一个选择是保留旧图像,这样 link 就不会损坏。使用它的主要问题是用户在网站上创建 posts 并在 posts 中对这些图像创建 link(posts 会定期更新,所以我不能post 上的一次性缓存和 post 中的图像)。图像根据与其关联的项目的新信息更新。一旦发生这种情况,linked 在 post 中的图像将显示过时的信息,并且他们每次都必须手动更新到新图像。因此,在这种情况下,让图像 link 与正在更新的图像保持一致是最佳选择

original_filename 在此上下文中是上传者刚刚收到的文件的名称。这是文件的原名

通过这样做:

 "#{model.id}-#{original_filename}" if original_filename.present?

您是在告诉 CarrierWave 每次都使用文件的新名称。听起来您希望给定模型每次都使用相同的文件名。因此,显而易见的选择就是完全丢弃 original_filename 并单独使用模型 ID。

但是,auto-generated 上传程序代码中 filename 方法上方的注释是这样说的:

  # Avoid using model.id or version_name here, see uploader/store.rb for details.

这导致我们...

  # Be careful using record ids as filenames. If the filename is stored in the database
  # the record id will be nil when the filename is set. Don't use record ids unless you
  # understand this limitation.

有点麻烦。除非你能保证你的模型总是有一个 id(如果它是新的就不会是真的)那么你不应该使用 model.id 来命名你的文件。

我建议您在初始化时为每个模型生成一个唯一的 file_identifier 字符串一次(只要 file_identifier 尚未设置),并使用这个唯一的字符串作为您的文件名, 例如

class Something < ActiveRecord::Base
  mount_uploader :image, SomeImageUploader

  after_initialize do
    unless self.file_identifier
      self.file_identifier = SecureRandom.hex(32)
    end
  end
end

...并在您的上传器中 class...

def filename
  model.file_identifier if original_filename
end

现在您上传的图片将始终覆盖同一个文件。但请注意:您刚刚丢失了图像扩展。这在我的现代版本的 Firefox 中似乎没问题(它可以通过查看图像 header 来猜测),但它可能不是最广泛兼容的解决方案。您可以采用 original_filename 的扩展名并将其添加到那里,但是现在如果有人上传了 png 然后又上传了 jpg(结果将是两个不同的文件),您又回到了原来的问题。

您可以在上传时转换为您选择的固定格式,这样文件名+扩展名将始终相同。

老实说,如果您接受文件在每次上传后都有一个新名称,并且只需将旧文件保留一段时间以继续支持拥有旧文件的用户,我认为您会过得更轻松link。 (无论如何,这些 link 会有多长时间?如果它位于缓存中,那么为什么只缓存生成的 HTML 而不缓存图像?)如果您曾经计划在您的应用程序和您的用户之间使用 CDN 服务。通常的模式是每次都使用新的唯一文件名对文件进行版本控制,CDN 将永久缓存该文件名。