2010-02-05 28 views
2

我有一个模型,让我们说Attachments,它使用attachment_fu来接受用户的文件上传。我想“深层复制”(或在Ruby-ese中深层克隆)Attachment,从而在“db_files”表中创建一个全新的二进制对象。Rails,Attachment_fu - 数据库存储附件的深层副本

我发现它还没有完全解决问题。此博客文章: http://www.williambharding.com/blog/rails/rails-faster-clonecopy-of-attachment_fu-images/

显示一种据称可用于基于文件系统的存储的方法。对于基于数据库的商店,“深层复制”失败。创建一个新的“附件”,但它使用预先存在的db_file_id,从而执行浅拷贝。

内attachment_fu的db_file_backend.rb我看到了保存方法:

 # 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”是一些Ruby的元编程魔法速记DbFile.new虽然我不能确认这(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 

这实际上工作正常克隆的对象,但遗憾的是所有针对常规,非克隆文件上传的测试都会失败。附件对象已创建,但没有数据写入db_file。理论是先保存父对象,然后再写db_file的东西,这样new_record?返回false。

因此,作为一个实验,我决定尝试:

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,但恐怕我不得不去掉兔子洞来弄清楚。任何想法或想法?

谢谢!

+0

注意:更优雅的解决方案是使用引用计数形式,并使所有Attachment obj指向相同的db_file_id。只有在没有附件指向它时删除db_file。嗯 – 2010-02-05 19:36:25

回答

0

好的,所以我没有搞清楚如何创建一个新的db_file(这在我们的特殊情况下是浪费的),而只是删除了db_file,如果没有更多的附件记录指向它的话。如果您允许某人“修改”附件db_file 原位,但这可能不合适,但由于我们不这样做,所以这很有用。

Technoweenie::AttachmentFu::Backends::DbFileBackend.module_eval do 
    protected 
    def destroy_file 
    if db_file && self.class.count(:conditions =>["id <> ? AND db_file_id = ?", self.id, db_file.id]) == 0 
     db_file.destroy 
    end 
    end 
end 
1

这只是说明build_db_file呼叫

正如你所料想的部分回应,build_db_file调用执行方法generated by creating a belongs_to association。该协会在这里创建:

def self.included(base) #:nodoc: 
    Object.const_set(:DbFile, Class.new(ActiveRecord::Base)) unless Object.const_defined?(:DbFile) 
    base.belongs_to :db_file, :class_name => '::DbFile', :foreign_key => 'db_file_id' 
end 

所以(db_file || build_db_file)语句采用现有的相关DbFile对象,或者创建如果它是零一个新的,和TEMP_DATA分配给它的二进制领域datatemp_data可能是包含表单数据的字节数组。

而且我有一个问题(我不能对你的问题发表评论) - 为什么不叫db_file.save!

db_file = DbFile.new :data => temp_data 

创建后?

+0

好问题。这是我的一个错误,虽然它不能解决问题:)谢谢! – 2010-02-09 16:54:51