Re-adding missing uploads to the database

D’accord, je l’ai résolu avec Claude et beaucoup de compliments. Je partage ce que j’ai fait afin d’aider toute autre personne ayant un problème similaire ou identique.

Je ne suis pas sûr que ce soit la méthode la plus astucieuse et optimale à utiliser, juste celle qui a fonctionné pour moi.

Veuillez faire attention et garder à l’esprit que je ne suis pas un expert mais un novice toujours en apprentissage.

Le problème (S3 → système de fichiers local)

Après la migration d’AWS S3 vers le système de fichiers local, de nombreuses images s’affichaient comme transparent.png. Les fichiers étaient toujours sur le disque, mais Discourse ne parvenait pas à les résoudre.

La cause profonde était une chaîne brisée :

  1. Messages avec des URL courtes upload:// (SHA1 encodé en base62).
  2. Base de données uploads mappant SHA1 → chemin de fichier local.
  3. Système de fichiers stockant les fichiers nommés d’après leur hachage SHA1,

La migration a déplacé les fichiers sur le disque correctement, mais aucun enregistrement DB uploads n’existait. Sans enregistrement correspondant, Discourse revient à transparent.png.

La solution (créer des enregistrements et réintégrer)

Créer les enregistrements d’upload manquants à partir des fichiers orphelins :

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

Réintégrer les messages qui référencent les uploads restaurés :

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

Régénérer les optimisations manquantes :

Après avoir corrigé les fichiers originaux, nous devons remplir les fichiers optimisés (1X, 2X, etc.).

rake uploads:regenerate_missing_optimized

Retour arrière sécurisé (juste au cas où)

Tous les enregistrements créés utilisent user_id: -1. Pour annuler :

Upload.where(user_id: -1).delete_all

delete_all ignore les callbacks, donc les fichiers du système de fichiers ne sont pas affectés.

J’ai utilisé destroy_all par erreur auparavant et cela a déclenché des callbacks qui ont déplacé les fichiers vers la corbeille.

J’en ai récupéré un individuellement que j’ai utilisé pour tester et reformuler mon approche.

3 « J'aime »