在Rails中对PostgreSQL的大对象进行建模

我需要在我的rails应用程序中保存数据库中的大对象。 我认为我可以在SQL中创建一个表

CREATE TABLE files ( id serial NOT NULL, name string NOT NULL, blob_oid oid NUT NULL ) 

然后将数据存储在Ruby中

 conn.exec("BEGIN") lo = conn.lo_import(data) conn.exec("COMMIT") file = File.new file.name = file_name; file.blob_oid = lo.id file.save 

首先,这是正确的吗? 其次,我如何描述File in Rails的模型。 Rails中Friend.blob_oid的数据类型是什么? 我可以使用Rails中的迁移创建文件表吗?

如果将Rails附带的ActiveRecord与其中一个适配器一起使用,则数据库类型到Rails或Ruby类型的唯一正式映射通常在适配器中的NATIVE_DATABASE_TYPES常量中定义,该常量通过其native_database_types方法返回。 对于Rails 3.2.x中的PostgreSQL,它位于ActiveRecord::ConnectionAdapters::PostgreSQLAdapter中。 因此,对于该适配器,Rails中的“二进制”类型映射到PG中的“bytea”类型。 对于某些类型,您可以使用名为activerecord-native_db_types_override的gem覆盖它映射到的数据库类型。 但是,我们想要使用大型物体,所以……

迁移

正如Jim Deville在评论中指出的那样,您可以在表格中指定自定义类型列,如:

 t.column :some_oid, 'blob_oid', :null => false 

如果您需要执行更多非标准操作,还可以使用execute("SQL GOES HERE;")来使用直接SQL创建表。 并且,如果您有一个现有的遗留模式或在迁移之外进行的SQL更改,请考虑使用structure.sql( config/application.rb config.active_record.schema_format = :sql选项,然后执行: rake db:structure:dump )。

大对象读/写/检查长度/删除

从以下url复制一些修改澄清等: https : //github.com/diogob/carrierwave-postgresql/blob/v0.1.0/lib/carrierwave/storage/postgresql_lo.rb :

更新 :我们可以但不需要在lo_read / lo_write / lo_lseek之前放置一个开头,并且在确保块中执行lo_close,因为每个PG文档 “在事务结束时保持打开的任何大对象描述符都将自动关闭”。 (感谢Diogo提供的信息)

  require 'pg' ... def read (...).transaction do lo = connection.lo_open(identifier) content = connection.lo_read(lo, file_length) connection.lo_close(lo) content end end def write(file) (...).transaction do lo = connection.lo_open(identifier, ::PG::INV_WRITE) size = connection.lo_write(lo, file.read) connection.lo_close(lo) size end end def delete connection.lo_unlink(identifier) end def file_length (...).transaction do lo = connection.lo_open(identifier) size = connection.lo_lseek(lo, 0, 2) connection.lo_close(lo) size end end 

而不是connection ,使用模型或基础的原始连接,例如ActiveRecord::Base.connection.raw_connection (请参阅此内容 )。

(...).transaction是在模型或基础上调用事务,例如ActiveRecord::Base.transaction (参见这个 )。

identifier是您需要传入/设置或从仅执行connection.lo_creat获取的oid。

其他例子/信息:

后者和此处的一些答案表明您可能需要考虑与数据库分开存储大型文件,例如,以便您可以使用云存储。 但是,如果仅将路径/ ID存储到不由 DB管理的外部文件,则会丢失ACID一致性(一个或多个DB记录可能指向一个或多个不存在的文件或者可能存在一个或多个文件在数据库中没有一个或多个关联的记录)。 在文件系统上存储文件的另一个参数是你可以流文件,但是PG大对象以postgres管理的方式在文件系统上存储文件,以确保ACID一致性并允许流式传输(你不能用普通的BLOB做) / Rails二进制类型)。 所以,这取决于; 有些人发现使用路径引用存储在单独的存储中是一个更好的选择,有些人更喜欢通过大对象的ACID一致性。

简单的方法

只需使用CarrierWave和carrierwave-postgresql 。