Re-adding missing uploads to the database

Ok, eu resolvi com o Claude e muitos elogios. Estou compartilhando o que fiz para ajudar qualquer outra pessoa com um problema semelhante ou o mesmo.

Não tenho certeza se este é o método mais inteligente e otimizado a ser usado, apenas o que funcionou para mim.

Por favor, tenha cuidado e tenha em mente que não sou um especialista, mas um novato sempre aprendendo.

O problema (S3 → sistema de arquivos local)

Após a migração do AWS S3 para o sistema de arquivos local, muitas imagens eram exibidas como transparent.png. Os arquivos estavam sempre no disco, mas o Discourse não conseguia resolvê-los.

A causa raiz era uma cadeia quebrada:

  1. Posts com URLs curtas upload:// (SHA1 codificado em base62).
  2. Banco de dados uploads mapeando SHA1 → caminho do arquivo local.
  3. Sistema de arquivos armazenando arquivos nomeados pelo seu hash SHA1,

A migração moveu os arquivos para o disco corretamente, mas não havia registros de DB uploads. Sem um registro correspondente, o Discourse recorre ao transparent.png.

A solução (criar registros e reprocessar)

Criar registros de upload ausentes a partir de arquivos órfãos:

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}"

Reprocessar posts que referenciam uploads restaurados:

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}"

Regenerar otimizados ausentes:

Após corrigir os arquivos originais, precisamos preencher os arquivos otimizados (1X, 2X, etc.).

rake uploads:regenerate_missing_optimized

Rollback seguro (só por precaução)

Todos os registros criados usam user_id: -1. Para desfazer:

Upload.where(user_id: -1).delete_all

delete_all ignora os callbacks, então os arquivos do sistema de arquivos não são afetados.

Anteriormente, usei destroy_all por engano e isso acionou callbacks que moveram os arquivos para a lixeira.

Recuperei um individual que usei para testar e reformulei minha abordagem.

3 curtidas