Rails 回形针如何删除附件?

我在 Rails3上使用的是 回形针(w/Amazons3)。我想删除一个现有的附件 而不是更换它使用更新操作。

我只找到了这个 给你的一个例子,它无法正常工作,无法删除,日志中也没有说明原因。我想在表单上做这样的事情:

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

(page 是模型的名称,image 是保存附件的属性名称)

但是我该如何检测这个复选框,更重要的是,我该如何删除这个图像呢!

54502 次浏览

First off, when you create a check_box in a form_for (which it looks like you are), then the form should by default send :image_delete as "1" if checked and "0" if unchecked. The method declaration looks like this:

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

Which shows that you can assign other values if you want to, but that is of course optional.

Secondly, the call to manually delete an attachment without deleting the model instance to which it is attached to is:

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

And to accomplish your way of deleting the images through a checkbox, perhaps add something like this to your Page model:

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

This way, when you create your form and add the :image_delete checkbox, it will load the default value "0" from the User instance. And if that field is checked then the controller will update the image_delete to "1" and when the User is saved, it will check if the image is to be deleted.

remember to add this to your Page model too:

attr_accessible :image_delete

has_attached_file :asset

=>

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

No need to destroy asset, Paperclip will do it.

In the form form.check_box(:delete_asset) will suffice.

This is Benoit's answer, but wrapped in a module, and covering the edge case of nested attribute models where the destroy tickbox is the only thing changed on the model.

It will apply to all attachments on the model.

# 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

Modified version of Paul's solution, to support Rails 5 custom attributes. I just wish there were a way to include the module at the top of the file, before has_attached_file definitions.

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

Was able to achieve this with less code, by just implementing a delete_attachment on the model's side.:

class MyModel < ApplicationRecord
has_attached_file :image


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