2

我有一个模型,比如说附件,它使用 attachment_fu 来接受用户上传的文件。我想“深度复制”(或在 Ruby-ese 中,深度克隆)一个附件,从而在“db_files”表中创建一个全新的二进制对象。

我发现这还不是一个完全解决的问题。这篇博文: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”是 DbFile.new 的一些 Ruby 元编程魔术速记,尽管我无法确认这一点(grepping 源显示没有提及这一点,我也无法在谷歌上找到它)。

我不太确定它在做什么,但我的理论是,作为“深拷贝”尝试的一部分(在链接代码中),正在从源 obj 复制 db_file,因此它只是触发保存而不是创造。

我最初的理论是父(附件)对象将在深拷贝尝试时设置为“新”,因此我做了类似的事情:

 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?返回假。

所以,作为一个实验,我决定尝试:

  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,但恐怕我将不得不深入兔子洞才能弄清楚。有什么想法或想法吗?

谢谢!!

4

2 回答 2

1

这只是解释build_db_file呼叫的部分响应

正如您所怀疑的,该build_db_file调用执行通过创建belongs_to关联生成的方法。关联在此处创建:

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对象,如果它为 nil,则创建一个新对象,并将 temp_data 分配给它的二进制字段data。这temp_data可能是包含表单数据的字节数组。

我有一个问题(我无法评论你的问题) - 你为什么不在db_file.save!创建它之后打电话

db_file = DbFile.new :data => temp_data

?

于 2010-02-09T15:23:25.757 回答
0

好的,所以我没有弄清楚如何创建一个新的 db_file(这在我们的特定情况下是浪费的),我只是对 destroy_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
于 2010-02-13T03:28:29.513 回答