Rails 和回形针,删除记录但不删除附件
我按照通常的方式使用导轨和回形针来保存图像。
当带有附件的记录被销毁时,附件也会从文件系统中删除。
99% 的情况下,这是正确的操作,但是在某些情况下,即使删除了数据库记录,我也需要将附件保留在系统中。
我想知道是否有人知道该怎么做。
我尝试在销毁记录之前通过 update_attribute 将附件字段设置为 nil,但 update_attribute 也会删除该文件。
一种方法是忽略所有回调,但是需要一些其他回调,这似乎有点太多了。任何人都知道更好的方法...
干杯。
I'm using rails and paperclip to save images, the usual way.
When a record with an attachment is destroyed, the attachment also gets deleted from the file system.
99% of the time this is the correct action, however there is a case where I need the attachment to remain in the system even though the db record is deleted.
I was wondering if anyone knew how to do this.
I've tried setting the attachment fields to nil via an update_attribute before destroying the record, but the update_attribute also delete the file.
One way would be to ignore all the callbacks, however some of the other call backs are needed and this seems a little too much. Anyone know any better ways...
Cheers.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可能想看看
Attachment#assign
(当您执行object.attachment = new_attachment
时调用)是如何在回形针中实现的。基本上,它会进行一些设置,然后调用
Attachment#clear
,然后保存新文件。Attachment#clear 将旧文件放入删除队列中,当您再次调用 save 时会处理该队列,您想要的只是避免调用clear,您可以通过编写一个跳过该行的新分配方法或通过猴子来实现修补
#clear
,使其成为无操作。理论上,您可以在您希望发生这种情况的实例上进行猴子修补,但在我看来,您可能希望在整个项目中都这样做。或者您可以清除保存处理队列的实例变量。该变量没有访问器,但执行
instance_variable_get
应该很简单you may want to take a look at how
Attachment#assign
(called when you doobject.attachment = new_attachment
) is implemented in paperclip.Basically, it makes a bit of setup, then calls
Attachment#clear
, then it saves the new file.Attachment#clear puts the old file in a deletion queue that is processed when you call save again, what you want is simply to avoid the call to clear, which you could do by either writing a new assign method which skips that line or by monkey patching
#clear
so that it becomes a no-op. In theory you could just monkey patch it on the instances where you want this to happen, but it seems to me you may want to do it for the whole project.Or you can clear the instance variable holding the processing queue. That variable does not have an accessor, but it should be trivial to do an
instance_variable_get
gem 允许您进行软删除:(
来自 paperclip)
软删除的文件保留
可以使用一个选项来保留附件,以便与软删除模型完美配合。 (acts_as_paranoid、偏执狂等)
这将防止模型被破坏时 some_attachment 被清除,因此当稍后恢复对象时它仍然存在。
The gem allows you to do a soft delete:
(from paperclip)
File Preservation for Soft-Delete
An option is available to preserve attachments in order to play nicely with soft-deleted models. (acts_as_paranoid, paranoia, etc.)
This will prevent some_attachment from being wiped out when the model gets destroyed, so it will still exist when the object is restored later.
对我来说,重写 Paperclip::Attachment#clear 方法并不能解决问题。我必须覆盖
Paperclip::Attachment#queue_all_for_delete
。正如 Alex Falke 所说,Paperclip 有
:preserve_files
选项,因此显然如果您想保留所有附件,您可以使用它而不是覆盖。如果您遇到特殊情况,则可以覆盖
#queue_all_for_delete
,但您必须有选择地执行此操作。猴子修补是全局性的,因此这不是最好的方法。我尝试使用改进来限制猴子修补范围,但词法范围并不能很好地适应我的用例。所以我最终得到了这个模块,它将自身注入到方法查找路径中,并有选择地定义或取消定义
#queue_all_for_delete
的无操作覆盖:使用它,您可以执行以下操作:
For me overriding the
Paperclip::Attachment#clear
method did not do the trick. I had to overridePaperclip::Attachment#queue_all_for_delete
.As Alex Falke said, Paperclip has the
:preserve_files
option, so obviously if you wanted to preserve all attachments you would use it instead of overriding.If you have a special case, overriding
#queue_all_for_delete
is the way to go, but you'll have to do it selectively. Monkey patching is global, so it is not the best approach. I tried to use refinements to limit the monkey patching scope, but the lexical scoping didn't play nicely with my use case.So I ended up with this module, which injects itself to the method lookup path and selectively defines or undefines a no-op override for
#queue_all_for_delete
:With it you can do something like:
将回形针生成的数据库字段(文件名、内容类型、文件大小)置空将不会保留该文件。 destroy 方法仍然会通过索引指向它。
在销毁记录之前,尝试将 id 更改为某个随机数(例如 999898)。如果抛出异常,也将字段清零。这样,记录将不再指向文件,并将在记录被销毁时保留下来。
Nil-ling the database fields that paperclip generates (file_name, content_type, file_size) would not keep the file. The destroy method will still point it through the index.
Try changing the id to some random number (e.g. 999898) before you destroy the record. If it throws exception, also nil the fields. That way the record will no longer points at the file and will remain as the record gets destroyed.
那么问题是这是怎么回事?您正在尝试实施撤消以便其他人可以删除然后取消删除?
我认为您的解决方案应该处理“清除”标志,然后如果清除标志为真,则每晚在批处理作业中删除。只要所有获取都是针对带有索引的clear = false 的记录,就不会影响性能。这个问题的解决方式给人一种“错误”的感觉。只是提供不同的视角。
So the question is what is going on? You are trying to implement undo so someone can delete and then undelete?
I would argue that your solution should be dealing with a "clear" flag and then deleting in a batch job nightly if the clear flag is true. Would not impact performance as long as all gets are for records where clear = false with an index. The question just has a feel of "wrongness" in the solution to it. Just offering a different perspective.
也许有点偏离主题:
如果附件存储在 S3 上 - 您只需覆盖
has_attached_file
方法并仅传递附件名称而不带任何选项。在这种情况下,回形针会认为文件存储在文件系统中,并且不会删除任何内容。也不例外。我知道这个解决方案可能有点老套/丑陋,但很简单并且有效。
Maybe a little bit off topic:
In case when attachment is stored on S3 - you can just override the
has_attached_file
method and pass only attachment name without any options. Paperclip will think in this case that file is stored in filesystem and will just delete nothing. Also no exception is raised.I know that this solution may be a little bit hacky/ugly but is simple and works.