Re-adding missing uploads to the database

好的,我通过 Claude 和大量的赞美解决了这个问题。我将分享我的做法,希望能帮助到遇到类似或相同问题的其他人。

我不确定这是不是最巧妙和最佳的使用方法,但它对我有效。

请小心并记住,我不是专家,而是一个不断学习的新手。

问题所在 (S3 → 本地文件系统)

从 AWS S3 迁移到本地文件系统后,很多图片显示为 transparent.png。文件总是在磁盘上,但 Discourse 无法解析它们。

根本原因是链条断裂:

  1. 带有 upload:// 短链接(base62 编码的 SHA1)的帖子
  2. 数据库中将 SHA1 映射到本地文件路径的 uploads 记录。
  3. 以其 SHA1 哈希命名的文件文件系统

迁移正确地将文件移动到了磁盘,但没有存在的 uploads 数据库记录。如果没有匹配的记录,Discourse 会回退到 transparent.png

解决方案 (创建记录并重新烘焙)

从孤立文件中创建缺失的上传记录:

dir = Rails.root.join("public", "uploads", "default", "original")
created = 0

Dir.glob(dir.join("**", "*")).select { |f| File.file?(f) }.each do |path|
  sha = File.basename(path, File.extname(path))
  next if Upload.find_by(sha1: sha)

  ext = File.extname(path).delete(".")
  relative = path.sub("#{Rails.root}/public", "")

  u = Upload.new
  u.sha1 = sha
  u.url = relative
  u.original_filename = File.basename(path)
  u.filesize = File.size(path)
  u.extension = ext
  u.user_id = -1
  u.save!(validate: false)

  created += 1
  puts "Created upload #{u.id}: #{sha}"
end

puts "Total created: #{created}"

重新烘焙引用了已恢复上传的帖子:

fixed_posts = 0

Upload.where(user_id: -1).find_each do |u|
  short = u.short_url
  next unless short

  Post.where("raw LIKE '%upload://%'").find_each do |p|
    urls = p.raw.scan(/upload:\/\/^[^\s\]\)]+/)
    urls.each do |url|
      decoded = Upload.sha1_from_short_url(url)
      if decoded == u.sha1
        p.rebake!
        fixed_posts += 1
        puts "Rebaked post #{p.id}"
        break
      end
    end
  end
end

puts "Total rebaked: #{fixed_posts}"

重新生成缺失的优化文件:

修复原始文件后,我们需要填充优化文件(1X、2X 等)。

rake uploads:regenerate_missing_optimized

安全回滚(以防万一)

所有创建的记录都使用 user_id: -1。要撤销:

Upload.where(user_id: -1).delete_all

delete_all 会跳过回调,因此文件系统中的文件不会被触动。

之前错误地使用了 destroy_all,它触发了将文件移至墓碑的回调。

我恢复了用于测试的单个文件,并重构了我的方法。

3 个赞