Rails Paperclip Wie lösche ich einen Anhang?

84

Ich verwende Paperclip (mit Amazon S3) auf Rails 3. Ich möchte einen vorhandenen Anhang löschen, ohne ihn durch eine Aktualisierungsaktion zu ersetzen .

Ich habe hier nur ein Beispiel dafür gefunden und konnte das nicht zum Laufen bringen, es wurde einfach nicht gelöscht und es gab nichts in den Protokollen, was sagen könnte, warum. Ich wollte so etwas auf dem Formular machen:

<%- unless @page.new_record? || !@page.image? -%>
    <%= f.check_box :image_delete, :label => 'Delete Image' %>
<%- end -%>

(Seite ist der Name des Modells, Bild ist der Attributname, der den Anhang enthält)

Aber wie erkenne ich dieses Kontrollkästchen und was noch wichtiger ist, wie lösche ich das Bild? Ich freue mich über jede Hilfe!

jyoseph
quelle

Antworten:

104

Wenn Sie zunächst ein Kontrollkästchen in einem Formular für erstellen (wie es aussieht), sollte das Formular standardmäßig Folgendes senden: image_delete als "1", wenn aktiviert, und "0", wenn nicht aktiviert. Die Methodendeklaration sieht folgendermaßen aus:

def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")

Das zeigt, dass Sie andere Werte zuweisen können, wenn Sie möchten, aber das ist natürlich optional.

Zweitens lautet der Aufruf zum manuellen Löschen eines Anhangs, ohne die Modellinstanz zu löschen, an die er angehängt ist:

@page.image.destroy #Will remove the attachment and save the model
@page.image.clear #Will queue the attachment to be deleted

Fügen Sie Ihrem Seitenmodell möglicherweise Folgendes hinzu, um die Bilder über ein Kontrollkästchen zu löschen:

class Page < ActiveRecord::Base
  has_attached_file :image

  before_save :destroy_image?

  def image_delete
    @image_delete ||= "0"
  end

  def image_delete=(value)
    @image_delete = value
  end

private
  def destroy_image?
    self.image.clear if @image_delete == "1"
  end
end

Auf diese Weise wird beim Erstellen Ihres Formulars und Hinzufügen des Kontrollkästchens: image_delete der Standardwert "0" aus der Benutzerinstanz geladen. Wenn dieses Feld aktiviert ist, aktualisiert der Controller image_delete auf "1" und prüft beim Speichern des Benutzers, ob das Image gelöscht werden soll.

DanneManne
quelle
Bezieht sich das Bild "Seite #" in diesem Beispiel auf ein anderes Modell mit dem has_attached_fileNamen "Bild" oder hat die Seite den Anhang "Bild"?
John Bachir
@page ist die Modellvariable mit has_attached_file: image, aber ich habe den Modellbenutzer aus irgendeinem Grund benannt. Ich werde ändern und aktualisieren, um zu klären.
DanneManne
Okay, das macht mehr Sinn :)
John Bachir
Ich verstehe nicht, warum Sie dort nicht einfach self.image.destroy ausführen - entfernt Clear die zugrunde liegende Datei, sondern behält die Metainformationen zum Bild im Seitenmodell bei? Warum willst du das tun? (und es scheint nicht so, wie es der Fragesteller tun möchte)
John Bachir
11
Dieser Ansatz hat auch bei mir funktioniert ... aber ich hatte ein Problem ... Wenn der Benutzer das Kontrollkästchen image_delete aktiviert und gleichzeitig ein neues Bild in das Formular einfügt, wird das alte Bild gelöscht und das neue Bild nicht gespeichert . Ich löste dies, indem ich die Bedingung in self.image.clear if @image_delete == "1" and !image.dirty?in destroy_image?Methode änderte
Zeeshan
97

has_attached_file :asset

=>

    attr_accessor :delete_asset
    before_validation { asset.clear if delete_asset == '1' }

Büroklammer muss nicht zerstört werden.

In der Form form.check_box(:delete_asset)wird ausreichen.

Benoit B.
quelle
3
Dies funktioniert und es ist einfacher als die @DanneManne Antwort IMHO. Sehr gut! :)
MetalElf0
Wie würden Sie eine Spezifikation dafür schreiben?
Hengjie
1
Vielen Dank ! Um mir dabei zu helfen, dies noch weiter has_attached_file :asset has_destroyable_file :asset zu config/initializers/ reduzieren
Sunny
2
Ich habe ein Problem mit dieser Methode zumindest durch accept_nested_attributes gefunden. before_validation wird bei einer verschachtelten Speicherung nicht ausgelöst, wenn keine anderen Attribute geändert wurden. Siehe meine Antwort unten für die Lösung
Paul Odeon
4
@ SurgePedroza Ich glaube, Sie müssen den Parameter zulassen: delete_asset, siehe guide.rubyonrails.org/…
sman591
12

Dies ist die Antwort von Benoit, die jedoch in ein Modul eingeschlossen ist und den Randfall verschachtelter Attributmodelle abdeckt, bei denen das Kontrollkästchen "Zerstören" das einzige ist, was am Modell geändert wurde.

Dies gilt für alle Anhänge des Modells.

# This needs to be included after all has_attached_file statements in a class
module DeletableAttachment
  extend ActiveSupport::Concern

  included do
    attachment_definitions.keys.each do |name|

      attr_accessor :"delete_#{name}"

      before_validation { send(name).clear if send("delete_#{name}") == '1' }

      define_method :"delete_#{name}=" do |value|
        instance_variable_set :"@delete_#{name}", value
        send("#{name}_file_name_will_change!")
      end

    end
  end

end
Paul Odeon
quelle
1
Ich weiß nicht, warum dies nicht mehr Beachtung gefunden hat. attachment_definitionshabe gerade mein Leben gerettet.
okay56k
Benötigt aber auch diese Zeile:attr_accessible :"delete_#{name}"
okay56k
2
Das obige Beispiel sollte sich in Ihrem Anliegen oder Modellordner befinden. In dem Modell, in dem Sie es möchten, fügen Sie einfach die Zeile include DeletableAttachmentunter den has_attached_fileAnweisungen hinzu
Paul Odeon
2
In Rails3 benötigen Sie auch attr_accessible: "delete _ # {name}"
Mateu
1
Denken :delete_<your_attribute>Sie daran, zuzulassen, wenn Sie starke Parameter in Ihrem Controller verwenden
ivanxuu
5

Denken Sie daran, dies auch Ihrem Seitenmodell hinzuzufügen:

attr_accessible :image_delete
Glenn McW
quelle
1

Geänderte Version von Pauls Lösung zur Unterstützung von benutzerdefinierten Rails 5-Attributen. Ich wünschte nur, es gäbe eine Möglichkeit, das Modul vor den has_attached_fileDefinitionen oben in die Datei aufzunehmen .

module Mixins
  module PaperclipRemover

    extend ActiveSupport::Concern

    included do
      attachment_definitions.keys.each do |name|

        attribute :"remove_#{name}", :boolean

        before_validation do
          self.send("#{name}=", nil) if send("remove_#{name}?")
        end

      end
    end

  end

end
JBlake
quelle
0

Konnte dies mit weniger Code erreichen, indem nur ein delete_attachmentauf der Modellseite implementiert wurde :.

class MyModel < ApplicationRecord
  has_attached_file :image

  def image_delete=(other)
    self.image = nil if other == "1" or other == true
  end
end
stwienert
quelle