Rails Paperclip จะลบไฟล์แนบได้อย่างไร?


84

ฉันใช้Paperclip (w / Amazon s3) บน Rails 3 ฉันต้องการลบไฟล์แนบที่มีอยู่โดยไม่ต้องแทนที่ด้วยการดำเนินการอัปเดต

ฉันพบเพียงตัวอย่างเดียวที่นี่และไม่สามารถใช้งานได้มันจะไม่ลบและไม่มีอะไรในบันทึกที่จะบอกว่าทำไม ฉันต้องการทำสิ่งนี้ในแบบฟอร์ม:

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

(หน้าคือชื่อของรุ่นรูปภาพคือชื่อแอตทริบิวต์ที่มีไฟล์แนบ)

แต่ฉันจะตรวจจับช่องทำเครื่องหมายนั้นได้อย่างไรและที่สำคัญกว่านั้นคือฉันจะลบภาพได้อย่างไร? ขอขอบคุณสำหรับความช่วยเหลือ!

คำตอบ:


104

ก่อนอื่นเมื่อคุณสร้างช่องทำเครื่องหมายใน form_for (ซึ่งดูเหมือนว่าคุณเป็น) แบบฟอร์มควรเป็นค่าเริ่มต้นส่ง: image_delete เป็น "1" หากเลือกและ "0" หากไม่เลือก การประกาศวิธีการมีลักษณะดังนี้:

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

ซึ่งแสดงให้เห็นว่าคุณสามารถกำหนดค่าอื่น ๆ ได้หากต้องการ แต่แน่นอนว่าเป็นทางเลือก

ประการที่สองการเรียกให้ลบไฟล์แนบด้วยตนเองโดยไม่ต้องลบอินสแตนซ์โมเดลที่แนบมาคือ:

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

และเพื่อให้บรรลุวิธีการลบภาพผ่านช่องทำเครื่องหมายให้เพิ่มสิ่งนี้ลงในโมเดลเพจของคุณ:

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

ด้วยวิธีนี้เมื่อคุณสร้างแบบฟอร์มและเพิ่มช่องทำเครื่องหมาย: image_delete จะโหลดค่าเริ่มต้น "0" จากอินสแตนซ์ผู้ใช้ และหากมีการตรวจสอบช่องนั้นคอนโทรลเลอร์จะอัปเดต image_delete เป็น "1" และเมื่อผู้ใช้ถูกบันทึกระบบจะตรวจสอบว่าจะลบรูปภาพหรือไม่


ในตัวอย่างนี้รูปภาพ Page # หมายถึงโมเดลอื่นที่has_attached_fileหรือเพจมีไฟล์แนบชื่อรูปภาพหรือไม่
John Bachir

@page เป็นตัวแปรโมเดลที่ has_attached_file: image แต่ดูเหมือนว่าฉันจะตั้งชื่อโมเดล User ด้วยเหตุผลบางประการ ฉันจะเปลี่ยนแปลงและอัปเดตเพื่อชี้แจง
DanneManne

เอาล่ะเข้าท่ากว่า :)
John Bachir

ฉันไม่เข้าใจว่าทำไมคุณไม่ทำแค่ self.image.destroy ที่นั่น - การล้างไฟล์ที่อยู่ข้างใต้จะลบออก แต่ยังคงรักษาข้อมูลเมตาเกี่ยวกับรูปภาพในโมเดลเพจไว้หรือไม่ ทำไมคุณถึงต้องการทำเช่นนี้? (และดูเหมือนว่านั่นจะไม่ใช่สิ่งที่ผู้ถามต้องการทำ)
John Bachir

11
วิธีนี้ใช้ได้ผลกับฉันเช่นกัน ... แต่ฉันประสบปัญหาหนึ่ง ... หากผู้ใช้ตรวจสอบช่องทำเครื่องหมาย image_delete และเพิ่มรูปภาพใหม่ในเวลาเดียวกันในแบบฟอร์มรูปภาพเก่าจะถูกลบและรูปภาพใหม่จะไม่ถูกบันทึก . ฉันแก้ไขสิ่งนี้โดยเปลี่ยนเงื่อนไขเป็นself.image.clear if @image_delete == "1" and !image.dirty?in destroy_image?method
Zeeshan

97

has_attached_file :asset

=>

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

ไม่จำเป็นต้องทำลายสินทรัพย์คลิปหนีบกระดาษจะทำ

ในรูปแบบ form.check_box(:delete_asset)จะพอเพียง


3
วิธีนี้ใช้งานได้และง่ายกว่าคำตอบของ @DanneManne IMHO ดีมาก! :)
MetalElf0

คุณจะเขียนข้อมูลจำเพาะสำหรับสิ่งนี้อย่างไร?
Hengjie

1
ขอบคุณ! เพื่อช่วยให้ฉันผอมลงมากขึ้นเพื่อ: has_attached_file :asset has_destroyable_file :asset ฉันสร้างตัวเริ่มต้นเพื่อเพิ่มในconfig/initializers/ gist.github.com/3954054
ซันนี่

2
ฉันพบปัญหากับวิธีนี้ผ่านอย่างน้อย accept_nested_attributes before_validation จะไม่ถูกทริกเกอร์ในการบันทึกที่ซ้อนกันหากไม่มีการเปลี่ยนแปลงแอตทริบิวต์อื่น ๆ ดูคำตอบของฉันด้านล่างสำหรับวิธีแก้ปัญหา
Paul Odeon

4
@SurgePedroza ฉันเชื่อว่าคุณต้องอนุญาตพารามิเตอร์: delete_asset ดูguide.rubyonrails.org/…
sman591

12

นี่คือคำตอบของ Benoit แต่ห่อหุ้มด้วยโมดูลและครอบคลุมขอบกรณีของโมเดลแอตทริบิวต์ที่ซ้อนกันซึ่งกล่องกาเครื่องหมายทำลายเป็นเพียงสิ่งเดียวที่เปลี่ยนแปลงในโมเดล

จะใช้กับไฟล์แนบทั้งหมดในรุ่น

# 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

1
ไม่รู้ว่าทำไมถึงไม่ได้รับความสนใจมากขึ้น attachment_definitionsแค่ช่วยชีวิตฉัน
okay56k

ต้องการบรรทัดนี้ด้วยเช่นกัน:attr_accessible :"delete_#{name}"
okay56k

2
ตัวอย่างข้างต้นควรอยู่ในข้อกังวลหรือโฟลเดอร์รุ่นของคุณ ในรุ่นที่คุณต้องการเพียงเพิ่มบรรทัดinclude DeletableAttachmentด้านล่างhas_attached_fileข้อความใด ๆ
Paul Odeon

2
ใน rail3 คุณจะต้องใช้ attr_accessible: "delete _ # {name}" ด้วย
Mateu

1
อย่าลืมอนุญาต:delete_<your_attribute>หากคุณใช้พารามิเตอร์ที่แข็งแกร่งในคอนโทรลเลอร์ของคุณ
ivanxuu


1

โซลูชันของ Paul เวอร์ชันดัดแปลงเพื่อรองรับคุณลักษณะที่กำหนดเองของ Rails 5 ฉันแค่หวังว่าจะมีวิธีรวมโมดูลไว้ที่ด้านบนของไฟล์ก่อนhas_attached_fileคำจำกัดความ

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

0

สามารถบรรลุสิ่งนี้ได้โดยใช้รหัสน้อยลงเพียงแค่ใช้delete_attachmentด้านข้างของโมเดล:

class MyModel < ApplicationRecord
  has_attached_file :image

  def image_delete=(other)
    self.image = nil if other == "1" or other == true
  end
end
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.