Rails, Attachment_fu - 数据库存储附件的深拷贝
我有一个模型,比方说 Attachments,它使用 Attachment_fu 接受用户上传的文件。我想“深度复制”(或者用 Ruby 语言来说,深度克隆)一个附件,从而在“db_files”表中创建一个全新的二进制对象。
我发现这还不是一个完全解决的问题。这篇博文: http://www.williambharding.com/blog /rails/rails-faster-clonecopy-of-attachment_fu-images/
显示了一种据称适用于基于文件系统的存储的方法。对于基于数据库的存储,“深层复制”失败。创建一个新的“附件”,但它使用预先存在的 db_file_id,从而执行浅复制。
在attachment_fu的db_file_backend.rb里面我看到了save方法:
# Saves the data to the DbFile model
def save_to_storage
if save_attachment?
(db_file || build_db_file).data = temp_data
db_file.save!
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
end
true
end
所以,我试图破译这个,我相信“build_db_file”是DbFile.new的一些Ruby元编程魔法简写,尽管我无法确认这一点(grepping源代码显示没有提到这一点,我在谷歌上也找不到它)。
我不太确定它在做什么,但我的理论是 db_file 是从源 obj 复制的,作为“深层复制”尝试的一部分(在链接代码中),因此它只是触发保存而不是触发创造。
我最初的理论是,父(附件)对象将在深度复制尝试时设置为“新”,因此我做了类似的事情:
def save_to_storage
if save_attachment?
if self.new_record?
db_file = DbFile.new :data => temp_data
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
end
end
true
end
这实际上对于克隆对象来说效果很好,但不幸的是,常规非克隆文件上传的所有测试都失败了。 Attachment 对象已创建,但没有数据写入 db_file。理论上是先保存父对象,然后再写入 db_file 的东西,因此 new_record?返回假。
因此,作为一个实验,我决定尝试:
def save_to_storage
if save_attachment?
if self.new_record?
db_file = DbFile.new :data => temp_data
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
else
(db_file || build_db_file).data = temp_data
db_file.save!
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
#end
end
true
end
这部分有效 - db_file 已填充,但随后我在 db_file.save 上收到错误! - 说 db_file 为零。
所以,我有点受阻。我可以做一些进一步的尝试和错误,但此时我对这个插件如何工作的理解有限。我真的没想到或不想花这么多时间在上面,所以我不愿意进一步尝试和探索 Attachment_fu,但我担心我将不得不深入兔子洞才能弄清楚。有什么想法或想法吗?
谢谢!!
I have a model, let's say Attachments, that uses attachment_fu to accept file uploads from the user. I want to "deep copy" (or in Ruby-ese, deep clone) an Attachment, thus creating a completely new binary object in the "db_files" table.
I've found that it is not quite a solved problem yet. This blog posting:
http://www.williambharding.com/blog/rails/rails-faster-clonecopy-of-attachment_fu-images/
Shows a method that allegedly works for filesystem based storage. For db-based stores, the "deep copy" fails. A new "Attachment" is created but it uses the pre-existing db_file_id, thus performing a shallow copy.
Inside attachment_fu's db_file_backend.rb I see the save method:
# Saves the data to the DbFile model
def save_to_storage
if save_attachment?
(db_file || build_db_file).data = temp_data
db_file.save!
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
end
true
end
So, I am trying to decipher this and I believe "build_db_file" is some Ruby metaprogramming magic shorthand for DbFile.new although I cannot confirm this (grepping the source shows no mention of this, nor can I find it on google).
I'm not quite sure what it is doing, but my theory is that the db_file is being copied from the source obj as part of the "Deep copy" attempt (in the linked code) thus it is simply triggering a save instead of a create.
My initial theory was that the parent (Attachment) object would be set to "new" upon a deep copy attempt, thus I did something like:
def save_to_storage
if save_attachment?
if self.new_record?
db_file = DbFile.new :data => temp_data
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
end
end
true
end
This actually works fine for cloned objects but unfortunately all the tests for regular, non cloned file uploads fail. The Attachment object is created but no data is written to db_file. Theory is that the parent object is saved first, then the db_file stuff is written later, thus new_record? returns false.
So, as an experiment I decided to try:
def save_to_storage
if save_attachment?
if self.new_record?
db_file = DbFile.new :data => temp_data
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
else
(db_file || build_db_file).data = temp_data
db_file.save!
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
#end
end
true
end
That works partially - the db_file is populated but then I get an error on db_file.save! - saying that db_file is nil.
So, I'm sort of stymied. I can do some further trial and error but at this point I've hit my limited understanding of how this plugin works. I really didn't expect or want to spend this much time on it so I am reluctant to try and explore attachment_fu any further, but I'm afraid I'm going to have to go down the rabbit hole to figure it out. Any ideas or thoughts?
Thanks!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这只是解释
build_db_file
调用的部分响应正如您所怀疑的,
build_db_file
调用执行一个方法 通过创建belongs_to
关联生成。关联是在此处创建的:因此
(db_file || build_db_file)
语句采用现有的关联DbFile
对象,如果为 nil,则创建一个新对象,并将 temp_data 分配给它的二进制字段data
。 temp_data 可能是包含表单数据的字节数组。我有一个问题(我无法评论你的问题) - 为什么你在使用 db_file.save 创建后不调用 db_file.save!
?
This is just a partial response explaining the
build_db_file
callAs you suspected, the
build_db_file
call executes a method generated by creating abelongs_to
association. The association is created here:So the
(db_file || build_db_file)
statement takes an existing associatedDbFile
object, or creates a new one if it's nil, and assigns the temp_data to its binary fielddata
. Thetemp_data
is probably the byte array with the data from the form.And I have one question (I can't comment on your question) - why don't you call
db_file.save!
after creating it with?
好吧,所以我没有弄清楚如何创建新的 db_file(这在我们的特定情况下是浪费的),而是只是对 destroy_file 进行了猴子修补,以便仅在没有更多附件记录指向它时才删除 db_file。如果您允许某人原位“修改”附件 db_file,这可能不合适,但由于我们不允许,所以这非常有效。
Okay, so instead of figuring out how to create a new db_file (which is wasteful in our particular case), I just monkey-patched destroy_file to only delete the db_file if there are no more attachment records pointing to it. This may not be appropriate if you allow someone to "modify" an attachment db_file in situ but since we don't, this works great.