如何删除Rails Paperclip附件?

86
我是在Rails 3上使用Paperclip(带有Amazon s3)。我想使用更新操作删除现有的附件而不替换它
我只找到了一个这里的示例,但无法使其工作。它只是无法删除,并且日志中没有任何信息。我想在表单上做这样的事情:
<%- unless @page.new_record? || !@page.image? -%>
    <%= f.check_box :image_delete, :label => 'Delete Image' %>
<%- end -%>

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

但是我该如何检测到复选框,更重要的是,我该如何删除这张图片?感谢任何帮助!

6个回答

107

首先,假设您在 form_for 中创建了一个 check_box(看起来是这样),那么表单默认情况下应发送 :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"。如果勾选了该字段,则控制器将将图像删除更新为 "1",并在保存用户时检查是否要删除图像。


在这个例子中,Page#image是指另一个具有“has_attached_file”属性的模型,还是Page本身有名为image的附件? - John Bachir
@page 是模型变量,其中包含了 has_attached_file :image,但由于某些原因我似乎将模型命名为 User。我会进行更改和更新以澄清。 - DanneManne
好的,那就更有意义了 :) - John Bachir
我不明白为什么你不直接在那里使用self.image.destroy -- clear是否会删除底层文件,但保留Page模型中图像的元信息?你为什么要这样做?(而且似乎这不是问题提问者想要做的) - John Bachir
11
这种方法对我也有效...但我遇到了一个问题...如果用户在表单中同时选中image_delete复选框并添加新图像,那么旧图像将被删除而新图像不会保存。我通过在destroy_image?方法中更改条件为self.image.clear if @image_delete == "1" and !image.dirty?来解决这个问题。 - Zeeshan
根据我的经验,@page.image.destroy 只会删除云端的附件。因此,你需要明确保存你的模型记录 @page.save。否则,你的记录仍然会被认为有一个附加的图像/文件,但生成的链接将指向错误。(Rails 4.1 / Paperclip 4.2.0 / Amazon S3) - Sylvain FARNAULT

98

has_attached_file :asset

=>

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

无需销毁资产,Paperclip 将会处理它。
在表单中,form.check_box(:delete_asset)就足够了。

3
我认为这个方法比@DanneManne的回答简单且有效。非常好! :) - MetalElf0
你会如何为此编写规范? - Hengjie
1
谢谢!为了帮助我进一步简化这个问题,可以使用以下代码: has_attached_file :asset has_destroyable_file :asset我创建了一个初始化程序,可以添加到 config/initializers/ 目录下。https://gist.github.com/3954054 - Sunny
2
我发现通过 accepts_nested_attributes 至少存在一个问题。如果没有修改其他属性,则在嵌套保存时 before_validation 不会被触发。请参见下面的答案以获取解决方案。 - Paul Odeon
我在Rails 4中一直收到这个错误。未经许可的参数:delete_asset - Serge Pedroza
4
@SurgePedroza 我认为你需要允许参数:delete_asset,请参考http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters。 - 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 简直救了我的命。 - t56k
但是还需要这一行:attr_accessible :"delete_#{name}" - t56k
2
上面的示例应该在您的concerns或model文件夹中。在您想要它的模型中,只需在任何has_attached_file语句下方添加一行include DeletableAttachment即可。 - Paul Odeon
2
在rails3中,你需要attr_accessible:“delete_#{name}”。 - Mateu
1
如果您在控制器中使用强参数,请记得允许 :delete_<your_attribute> - ivanxuu
显示剩余4条评论

5

记得将这个添加到你的页面模型中:

attr_accessible :image_delete

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接