代码之家  ›  专栏  ›  技术社区  ›  Matt Rogish

Rails,附件-数据库存储附件的深度副本

  •  2
  • Matt Rogish  · 技术社区  · 15 年前

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

    我发现这个问题还没有完全解决。此日志: http://www.williambharding.com/blog/rails/rails-faster-clonecopy-of-attachment_fu-images/

    显示一种据称适用于基于文件系统的存储的方法。对于基于数据库的存储,“深度复制”失败。创建了一个新的“附件”,但它使用了预先存在的db_文件ID,因此执行了一个浅拷贝。

    在附件的db_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”是db file.new的一个Ruby元编程的神奇缩写,尽管我不能证实这一点(grepping源代码没有提到这个,也不能在谷歌上找到它)。

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

    我最初的理论是,通过深度复制尝试,父(附件)对象将设置为“新”,因此我做了如下操作:

     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_文件,这样就有了新的_记录?返回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
    

    这是部分工作-数据库文件被填充,但我在数据库文件上得到一个错误。保存!-说数据库文件是零。

    所以,我有点困惑。我可以做一些进一步的尝试和错误,但在这一点上,我对这个插件是如何工作的了解有限。我真的没想到也不想在上面花这么多时间,所以我不想再去探索依恋,但恐怕我得去兔子洞里想办法。有什么想法或想法吗?

    谢谢!!

    2 回复  |  直到 15 年前
        1
  •  1
  •   Matt    15 年前

    这只是一个部分反应,解释了 build_db_file 呼叫

    正如你怀疑的那样, Bug文件 调用执行方法 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 .这个 temp_data 可能是包含表单中数据的字节数组。

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

    db_file = DbFile.new :data => temp_data
    

    ?

        2
  •  0
  •   Matt Rogish    15 年前

    好吧,所以我不想弄清楚如何创建一个新的db_文件(这在我们的特定案例中是浪费的),我只是在没有更多的附件记录指向它的情况下,修改了destroy_文件,只删除db_文件。如果您允许某人“修改”附件数据库文件,这可能不合适。 就地 但既然我们不这么做,这就很好了。

    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