Re-adding missing uploads to the database

Okay, ich habe es mit Claude und viel Lob gelöst. Ich teile, was ich getan habe, um jedem mit einem ähnlichen oder demselben Problem zu helfen.

Ich bin mir nicht sicher, ob dies die cleverste und optimalste Methode ist, nur die, die für mich funktioniert hat.

Bitte seien Sie vorsichtig und denken Sie daran, dass ich kein Experte, sondern ein Anfänger bin, der immer lernt.

Das Problem (S3 → lokales Dateisystem)

Nach der Migration von AWS S3 auf das lokale Dateisystem wurden viele Bilder als transparent.png angezeigt. Die Dateien waren immer auf der Festplatte vorhanden, aber Discourse konnte sie nicht auflösen.

Die eigentliche Ursache war eine fehlerhafte Kette:

  1. Beiträge mit upload:// Kurz-URLs (base62-kodiertes SHA1).
  2. Datenbank uploads-Zuordnung SHA1 → lokaler Dateipfad.
  3. Dateisystem, das Dateien speichert, die mit ihrem SHA1-Hash benannt sind.

Die Migration hat die Dateien korrekt auf die Festplatte verschoben, aber es gab keine uploads-DB-Einträge. Ohne einen passenden Eintrag fällt Discourse auf transparent.png zurück.

Die Lösung (Datensätze erstellen und erneut backen)

Fehlende Upload-Datensätze aus verwaisten Dateien erstellen:

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

Beiträge, die wiederhergestellte Uploads referenzieren, erneut backen:

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\s]+?(?=[ \]]|$)/) # Angepasst, um besser mit verschiedenen Trennzeichen umzugehen
    urls.each do |url|
      decoded = Upload.sha1_from_short_url(url.first) # scan gibt eine Array von Matches zurück
      if decoded == u.sha1
        p.rebake!
        fixed_posts += 1
        puts "Rebaked post #{p.id}"
        break
      end
    end
  end
end

puts "Total rebaked: #{fixed_posts}"

Fehlende optimierte Dateien neu generieren:

Nachdem die ursprünglichen Dateien korrigiert wurden, müssen wir die optimierten Dateien (1X, 2X usw.) auffüllen.

rake uploads:regenerate_missing_optimized

Sicheres Rollback (nur für den Fall)

Alle erstellten Datensätze verwenden user_id: -1. Zum Rückgängigmachen:

Upload.where(user_id: -1).delete_all

delete_all überspringt Rückrufe, sodass die Dateien im Dateisystem unberührt bleiben.

Zuvor wurde versehentlich destroy_all verwendet, was Rückrufe auslöste, die Dateien in den Papierkorb verschoben haben.

Ich habe eine einzelne Datei, die ich zum Testen verwendet habe, wiederhergestellt und meinen Ansatz neu formuliert.

3 „Gefällt mir“