Rails Paperclip làm thế nào để xóa tệp đính kèm?


84

Tôi đang sử dụng Kẹp giấy (w / Amazon s3) trên Rails 3. Tôi muốn xóa tệp đính kèm hiện có mà không thay thế nó bằng hành động cập nhật.

Tôi chỉ tìm thấy một ví dụ về điều này ở đây và không thể làm cho điều đó hoạt động, nó sẽ không xóa và không có gì trong nhật ký để nói lý do. Tôi muốn làm điều gì đó như thế này trên biểu mẫu:

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

(trang là tên của mô hình, hình ảnh là tên thuộc tính chứa tệp đính kèm)

Nhưng làm cách nào để phát hiện hộp kiểm đó và quan trọng hơn, làm cách nào để xóa hình ảnh? Tôi đánh giá cao sự giúp đỡ!

Câu trả lời:


104

Trước hết, khi bạn tạo check_box trong form_for (trông giống như bạn), thì theo mặc định, biểu mẫu phải gửi: image_delete là "1" nếu được chọn và "0" nếu bỏ chọn. Khai báo phương thức trông như thế này:

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

Điều này cho thấy rằng bạn có thể gán các giá trị khác nếu bạn muốn, nhưng đó tất nhiên là tùy chọn.

Thứ hai, lệnh gọi để xóa thủ công tệp đính kèm mà không xóa cá thể mô hình mà nó được đính kèm là:

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

Và để thực hiện cách xóa hình ảnh thông qua hộp kiểm, có thể thêm một cái gì đó như thế này vào mô hình Trang của bạn:

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

Bằng cách này, khi bạn tạo biểu mẫu của mình và thêm hộp kiểm: image_delete, nó sẽ tải giá trị mặc định "0" từ cá thể Người dùng. Và nếu trường đó được chọn thì bộ điều khiển sẽ cập nhật image_delete thành "1" và khi Người dùng được lưu, nó sẽ kiểm tra xem hình ảnh có bị xóa hay không.


Trong ví dụ này, hình ảnh của Trang # có tham chiếu đến một mô hình khác has_attached_filehay Trang có tệp đính kèm, hình ảnh có tên không?
John Bachir

@page là biến mô hình has_attached_file: image, nhưng tôi dường như đã đặt tên cho mô hình là Người dùng vì lý do nào đó. Tôi sẽ thay đổi và cập nhật để làm rõ.
DanneManne

Được rồi, có ý nghĩa hơn :)
John Bachir

Tôi không hiểu tại sao bạn không thực hiện self.image.destroy ở đó - xóa tệp bên dưới mà vẫn duy trì thông tin meta về hình ảnh trong mô hình Trang? Tại sao bạn muốn làm điều này? (và nó không có vẻ như vậy của những gì các Asker câu hỏi muốn làm)
John Bachir

11
Cách tiếp cận này cũng hiệu quả với tôi ... nhưng tôi gặp phải một vấn đề ... nếu người dùng chọn hộp kiểm image_delete và đồng thời thêm hình ảnh mới vào biểu mẫu, thì hình ảnh cũ sẽ bị xóa và hình ảnh mới không được lưu . Tôi giải quyết điều này bằng cách thay đổi điều kiện để self.image.clear if @image_delete == "1" and !image.dirty?trong destroy_image?phương pháp
Zeeshan

97

has_attached_file :asset

=>

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

Không cần phải tiêu hủy tài sản, Kẹp giấy sẽ làm điều đó.

Trong biểu mẫu form.check_box(:delete_asset)sẽ đủ.


3
Điều này hoạt động và nó đơn giản hơn IMHO câu trả lời @DanneManne. Rất tốt! :)
MetalElf 0

Làm thế nào bạn sẽ viết một thông số kỹ thuật cho điều này?
Hengjie

1
Cảm ơn ! Để giúp tôi mỏng này xuống nhiều hơn để: has_attached_file :asset has_destroyable_file :asset Tôi tạo ra một initializer để thêm vào config/initializers/ gist.github.com/3954054
Nắng

2
Tôi đã tìm thấy sự cố với phương pháp này thông qua accept_nested_attributes ít nhất. before_validation không được kích hoạt trên một bản lưu lồng nhau nếu không có thuộc tính nào khác được thay đổi. Xem câu trả lời của tôi bên dưới để biết giải pháp
Paul Odeon

4
@SurgePedroza Tôi tin rằng bạn cần cho phép tham số: delete_asset, xem Guide.rubyonrails.org/…
sman591

12

Đây là câu trả lời của Benoit, nhưng được bao bọc trong một mô-đun và bao gồm trường hợp cạnh của các mô hình thuộc tính lồng nhau trong đó hộp đánh dấu hủy là thứ duy nhất được thay đổi trên mô hình.

Nó sẽ áp dụng cho tất cả các tệp đính kèm trên mô hình.

# 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
Không biết tại sao điều này không được chú ý nhiều hơn. attachment_definitionsvừa cứu sống tôi.
okay56k

Cần dòng này quá mặc dù:attr_accessible :"delete_#{name}"
okay56k

2
Ví dụ trên nên nằm trong thư mục mối quan tâm hoặc mô hình của bạn. Trong mô hình nơi bạn muốn nó chỉ cần thêm dòng include DeletableAttachmentdưới bất kỳ has_attached_filebáo cáo
Paul Odeon

2
Trong rails3, bạn cũng sẽ cần attr_accessible: "delete _ # {name}"
Mateu

1
Hãy nhớ cho phép :delete_<your_attribute>nếu bạn đang sử dụng các thông số mạnh trong bộ điều khiển của mình
ivanxuu

5

nhớ thêm cái này vào mô hình Trang của bạn nữa:

attr_accessible :image_delete

1

Phiên bản sửa đổi của giải pháp Paul, để hỗ trợ Rails 5 thuộc tính tùy chỉnh. Tôi chỉ ước có một cách để đưa mô-đun vào đầu tệp, trước các has_attached_fileđịnh nghĩa.

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

Có thể đạt được điều này với ít mã hơn, chỉ bằng cách triển khai một delete_attachmentbên của mô hình:

class MyModel < ApplicationRecord
  has_attached_file :image

  def image_delete=(other)
    self.image = nil if other == "1" or other == true
  end
end
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.