Rails回形针如何删除附件?


84

我正在Rails 3上使用Paperclip(w / Amazon s3)。我想删除现有附件而不使用更新操作替换它

我只发现了这样的一个实例在这里,不能得到那个工作,它只是不会删除,并没有什么在日志中说为什么。我想在表单上执行以下操作:

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

(页面是模型的名称,图像是保存附件的属性名称)

但是,如何检测该复选框,更重要的是,如何删除该图像?感谢您的帮助!

Answers:


104

首先,当您在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

为了完成通过复选框删除图像的方式,也许可以将以下内容添加到Page模型中:

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复选框时,它将从User实例中加载默认值“ 0”。如果选中了该字段,则控制器会将image_delete更新为“ 1”,并且在保存用户时,它将检查是否要删除图像。


在此示例中,Page#image是否引用了另一个模型has_attached_file,或者Page是否具有名为image的附件?
John Bachir

@page是具有has_attached_file:image的模型变量,但是由于某种原因,我似乎已将模型用户命名为。我将进行更改和更新以进行澄清。
DanneManne 2011年

好的,这更有意义:)
John Bachir

我不明白为什么您不只在那儿做self.image.destroy -清除是否删除了底层文件,而是在Page模型中维护了有关图像的元信息?你为什么想做这个?(而且看来这不是问问者要解决的问题)
John Bachir

11
这种方法对我也有效...但是我遇到了一个问题...如果用户选中image_delete复选框并同时在表单中添加新图像,则旧图像将被删除,而新图像将不被保存。我通过将条件更改为self.image.clear if @image_delete == "1" and !image.dirty?indestroy_image?方法来解决此问题
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回答恕我直言更简单。很好!:)
MetalElf0 2012年

您将如何为此编写规格?
恒街

1
谢谢 !为了帮助我进一步简化工作:has_attached_file :asset has_destroyable_file :asset 我创建了一个初始化程序添加到config/initializers/ gist.github.com/3954054
晴朗

2
我至少通过accepts_nested_attributes发现了此方法的问题。如果未更改其他属性,则嵌套存储不会触发before_validation。请参阅我的回答下面的解决方案
保罗剧场

4
@SurgePedroza我相信你需要允许参数:delete_asset,看guides.rubyonrails.org/...
sman591

12

这是Benoit的答案,但包装在一个模块中,涵盖了嵌套属性模型的边缘情况,在该属性中,destrok tickbox是模型上唯一更改的东西。

它将应用于模型上的所有附件。

# 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 2014年

不过也需要此行:attr_accessible :"delete_#{name}"
okay56k 2014年

2
上面的示例应该在您的关注点或模型文件夹中。在你想它只是添加行模式include DeletableAttachment下的任何has_attached_file声明
保罗剧场

2
在rails3中,您还需要attr_accessible:“ delete _#{name}”
Mateu 2014年

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在模型侧实现a就可以用更少的代码来实现这一点:

class MyModel < ApplicationRecord
  has_attached_file :image

  def image_delete=(other)
    self.image = nil if other == "1" or other == true
  end
end
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.