Paperclip附件在销毁后未被删除

4
使用Paperclip(v4.2.0)保存的附件在模型被销毁时未能从磁盘中删除,其他人是否也遇到了这个问题?一切都按预期运行,但文件并没有从磁盘中删除。非常感谢任何帮助或想法!
模型:
class Attachment < ActiveRecord::Base
  belongs_to :article

  has_attached_file :file, { :preserve_files => "false" }
  do_not_validate_attachment_file_type :file
end

class Article < ActiveRecord::Base
  belongs_to :topic
  belongs_to :subtopic
  belongs_to :author
  has_many :attachments, :dependent => :destroy
  accepts_nested_attributes_for :attachments, allow_destroy: true, reject_if: lambda { |a| a[:file].blank? }

  validates :topic_id, presence: true
  validates :title, presence: true, length: { maximum: 16 }
  validates :subtitle, length: { maximum: 20 }
  validates :content, presence: true
end

文章控制器中的销毁操作:

def destroy
  @article = Article.find(params[:id])
  begin
    # first delete the attachments from disk
    @article.attachments.each do |a|
      a.file.destroy
    end
    @article.destroy
  rescue
    flash[:danger] = "Unable to delete article"
  else
    flash[:success] = "Article deleted"
  end
  redirect_to admin_articles_url
end

你尝试过 @article.attachments.destroy 吗? - Rajesh Omanakuttan
刚刚尝试了您建议的@article.attachments.destroy(以及下面Gagan的建议),但仍然无法正常工作。数据库中的记录已被删除,但保存在磁盘上的文件仍然存在。 - NateQ
5个回答

2

在删除文件之前,您需要将附件的“file”属性设置为nil,以便从磁盘中删除已上传的文件。

因此,您的代码应该像这样:

Articles控制器中的destroy操作:

def destroy
  @article = Article.find(params[:id])
  begin
    # first delete the attachments from disk
    @article.attachments.each do |a|
     a.file = nil
     a.save
    end
    @article.destroy
  rescue
    flash[:danger] = "Unable to delete article"
  else
    flash[:success] = "Article deleted"
  end
  redirect_to admin_articles_url
 end

按照您的建议尝试了,但仍然无效。实际上,我之前尝试过类似的方法,即设置a.file=nil,然后保存a,正如Paperclip自己的文档所建议的那样。但是它没有任何效果。 - NateQ
@NateQ 你是对的,抱歉,在将其设置为nil后需要保存。我已经测试过了,即使我直接在对象上使用destroy而没有将文件属性设置为nil,它也可以很好地工作。我认为问题来自于:preserve_files =>“false”,你应该将其删除并再次尝试,它应该可以工作,文档说要使用preserve_files并将其设置为“true”以保留文件,没有关于设置:preserve_files为false以避免它的内容。 - Moustafa Sallam
@NateQ 我想知道这个对你是否有效,请告诉我。 - Moustafa Sallam
是的,终于成功了,谢谢!不过我不确定为什么,Paperclip文档说:preserve_files默认已经设置为false,所以明确将其设置为false会产生任何影响是相当奇怪的。之前我已经尝试过多次没有设置:preserve_files选项,但那时它并没有起作用。看来问题的核心是在控制器中应该使用'a.file = nil'而不是'a.file.destroy'。 - NateQ
1
我认为问题在于 :preserve_files 被设置为字符串 "false",而不是布尔值 false(即没有引号)。所有字符串都被视为 true。 - Michael Keenan

1

提出:

  def destroy
    self.transaction do
      self.images.destroy_all
      super
    end
  end

self.images 是带有附件的记录集合。 最重要的是 self.transaction do ...,因为如果由于任何原因 super(原始的 destroy)失败,它不会从硬盘上删除文件。它会等待提交。


1
尝试将preserve_files选项添加为“false”字符串 < p > < code > has_attached_file :file,:preserve_files =>“false”


0

你也可以使用 before_destroy 回调函数

例如

class User < ActiveRecord::Base
 before_destroy :delete_image

 has_attached_file :image,
              path: "/attachments/:class/:attachment/:style/:filename"

 validates_attachment_content_type :image, content_type: \Aimage\/.*\z/

 private

 def delete_image
   self.image = nil
   self.save
 end
end

那么每当模型类的实例被销毁时,附件将首先被删除。


0
尝试像这样做:

def destroy
    @article = Article.find(params[:id])
    @article.attachments.destroy
    @article.destroy
  respond_to do |format|
      format.html { redirect_to admin_articles_url }
    end
end

@article = Article.find(params[:id]) 会找到你想要删除的文章。 @article.attachments 会收集与该特定文章相关的所有附件。

注意:在销毁所有附件之后,必须销毁@article。如果你在@article.attachments.destroy之前写@article.destroy,那么它会报错,因为@article未找到。

由于你在Article模型中提到了has_many :attachments, :dependent => :destroy,所以我认为不需要编写@article.attachments.destroy,因为销毁@article将删除与其相关的所有附件。


仍然无法正常工作。所有记录已经从数据库中正确删除(与之前一样),但是保存的文件仍然存在于磁盘上。 - NateQ
本地硬盘,具体来说是:public/system/files/000/000/0xx/original,其中xx是附件的ID。 - NateQ

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