我使用rails和paperclip来保存图像,这是常用的方式。
当销毁附件的记录时,附件也会从文件系统中删除。
99%的时间这是正确的操作,但是有一种情况我需要附件保留在系统中,即使删除了db记录。
我想知道是否有人知道如何做到这一点。
在销毁记录之前,我尝试通过update_attribute将附件字段设置为nil,但update_attribute也会删除该文件。
一种方法是忽略所有的回调,但是需要一些其他回调,这看起来有点太多了。任何人都知道更好的方式......
干杯。
答案 0 :(得分:3)
您可能想看看在回形针中如何实现Attachment#assign
(在object.attachment = new_attachment
时调用)。
基本上,它会进行一些设置,然后调用Attachment#clear
,然后保存新文件。
附件#clear将旧文件放入再次调用save时处理的删除队列中,你想要的只是避免调用clear,你可以通过编写一个新的assign方法来跳过该行或者通过猴子修补#clear
以使其成为无操作。从理论上讲,你可以在想要发生这种情况的实例上修补它,但在我看来,你可能想要为整个项目做这件事。
或者您可以清除保存处理队列的实例变量。该变量没有访问器,但执行instance_variable_get
答案 1 :(得分:1)
禁止paperclip生成的数据库字段(file_name,content_type,file_size)不保留文件。 destroy方法仍会指向它通过索引。
在销毁记录之前,尝试将id更改为某个随机数(例如999898)。如果它抛出异常,也会使字段为零。这样,记录将不再指向文件,并将在记录被销毁时保留。
答案 2 :(得分:1)
所以问题是发生了什么?您正在尝试实施撤消,以便有人可以删除然后取消删除?
我认为你的解决方案应该处理一个“清除”标志,然后如果clear标志为真,则每晚在批处理作业中删除。只要所有获取都是针对带有索引的clear = false的记录,就不会影响性能。这个问题在解决方案中只是有一种“错误”的感觉。只是提供不同的视角。
答案 3 :(得分:1)
可能有点偏离主题:
如果附件存储在S3上 - 您可以覆盖has_attached_file
方法并仅传递附件名称而不使用任何选项。在这种情况下,Paperclip会认为文件存储在文件系统中并且不会删除任何内容。也没有例外。
我知道这个解决方案可能有点hacky /丑陋,但很简单且有效。
答案 4 :(得分:1)
gem允许您进行软删除:
(来自paperclip)
有一个选项可用于保存附件,以便与软删除模型很好地配合使用。 (acts_as_paranoid,偏执狂等)
has_attached_file :some_attachment, {
:preserve_files => "true",
}
这样可以防止在模型被破坏时消除some_attachment,因此在稍后恢复对象时它仍然存在。
答案 5 :(得分:1)
对我来说,重写Paperclip::Attachment#clear
方法并不能解决问题。我不得不覆盖Paperclip::Attachment#queue_all_for_delete
。
正如Alex Falke所说,Paperclip有:preserve_files
选项,所以很明显,如果你想保留所有附件,你会使用它而不是覆盖。
如果您有特殊情况,请覆盖#queue_all_for_delete
,但您必须选择性地执行此操作。猴子修补是全球性的,因此它不是最好的方法。我试图使用改进来限制猴子修补范围,但词法范围并没有很好地适应我的用例。
所以我最终得到了这个模块,它将自身注入到方法查找路径中,并有选择地定义或取消定义#queue_all_for_delete
的无操作覆盖:
module PaperclipKeepAttachment
def self.with_patch
patch
add_override
yield
ensure
remove_override
end
def self.patch
me = self
Paperclip::Attachment.class_eval{ prepend me } unless Paperclip::Attachment.ancestors.include?(me)
end
def self.add_override
define_method(:queue_all_for_delete) do
# no-op
end
end
def self.remove_override
remove_method(:queue_all_for_delete)
end
end
有了它,你可以做类似的事情:
PaperclipKeepAttachment.with_patch do
# The record will be destroyed but the attachment kept intact
first_record.destroy
end
# The record will be destroyed and the attachment removed
second_record.destroy