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 :
- Messages avec des URL courtes
upload://(SHA1 encodé en base62). - Base de données
uploadsmappant SHA1 → chemin de fichier local. - 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_allpar 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.