【问题标题】:Rails and paperclip, delete the record but don't delete the attachmentRails 和回形针,删除记录但不删除附件
【发布时间】:2011-05-16 07:56:23
【问题描述】:

我使用导轨和回形针来保存图像,通常的方式。

当带有附件的记录被销毁时,附件也会从文件系统中删除。

99% 的情况下这是正确的操作,但是在某些情况下,即使删除了 db 记录,我仍需要将附件保留在系统中。

我想知道是否有人知道如何做到这一点。

在销毁记录之前,我尝试通过 update_attribute 将附件字段设置为 nil,但 update_attribute 也会删除文件。

一种方法是忽略所有回调,但是需要其他一些回调,这似乎有点太多了。任何人都知道任何更好的方法...

干杯。

【问题讨论】:

    标签: ruby-on-rails ruby image-processing callback paperclip


    【解决方案1】:

    您可能想看看Attachment#assign(在您执行object.attachment = new_attachment 时调用)是如何在回形针中实现的。 基本上,它会进行一些设置,然后调用Attachment#clear,然后保存新文件。

    Attachment#clear 将旧文件放入删除队列中,当您再次调用 save 时会处理该队列,您想要的只是避免调用 clear,您可以通过编写一个跳过该行的新分配方法来做到这一点或通过猴子修补#clear 使其变为无操作。从理论上讲,您可以在希望发生这种情况的实例上对其进行修补,但在我看来,您可能希望为整个项目执行此操作。

    或者您可以清除保存处理队列的实例变量。该变量没有访问器,但执行instance_variable_get 应该很简单

    【讨论】:

      【解决方案2】:

      gem 允许您进行软删除:

      (来自paperclip

      为软删除保留文件

      可以使用一个选项来保留附件,以便与软删除的模型很好地配合使用。 (acts_as_paranoid、偏执狂等)

      has_attached_file :some_attachment, {
          preserve_files: true,
      }
      

      这将防止 some_attachment 在模型被破坏时被清除,因此在稍后恢复对象时它仍然存在。

      【讨论】:

      • True 不应该是字符串。
      • 已修复!谢谢@yekta
      【解决方案3】:

      回形针生成的数据库字段(file_name、content_type、file_size)不会保留文件。 destroy 方法仍将通过索引指向它。

      在销毁记录之前,尝试将 id 更改为某个随机数(例如 999898)。如果它抛出异常,也 nil 字段。这样,记录将不再指向文件,并在记录被销毁时保留。

      【讨论】:

        【解决方案4】:

        所以问题是发生了什么?您正在尝试实施撤消,以便有人可以删除然后取消删除?

        我认为您的解决方案应该处理“清除”标志,然后如果清除标志为真,则每晚在批处理作业中删除。只要所有获取都是针对带有索引的 clear = false 的记录,就不会影响性能。这个问题只是在解决它时有一种“错误”的感觉。只是提供不同的视角。

        【讨论】:

          【解决方案5】:

          可能有点跑题了:

          如果附件存储在 S3 上 - 您可以覆盖 has_attached_file 方法并仅传递附件名称而无需任何选项。在这种情况下,Paperclip 会认为文件存储在文件系统中,并且不会删除任何内容。也不例外。

          我知道这个解决方案可能有点笨拙/丑陋,但简单且有效。

          【讨论】:

            【解决方案6】:

            对我来说,重写 Paperclip::Attachment#clear 方法并没有成功。我不得不覆盖Paperclip::Attachment#queue_all_for_delete

            正如 Alex Falke 所说,Paperclip 具有 :preserve_files 选项,因此很明显,如果您想保留所有附件,则可以使用它而不是覆盖。

            如果您有特殊情况,覆盖#queue_all_for_delete 是可行的方法,但您必须有选择地执行此操作。 Monkey patching 是全球性的,所以它不是最好的方法。我尝试使用改进来限制猴子修补范围,但词法范围与我的用例并没有很好地配合。

            所以我最终得到了这个模块,它将自身注入到方法查找路径中,并有选择地定义或取消定义 #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
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-10-24
              • 2011-10-23
              • 1970-01-01
              • 2016-11-08
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多