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

时间:2013-02-07 05:13:21

标签: ruby-on-rails postgresql blob

我需要在我的rails应用程序中保存db中的大对象。我认为我可以在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中的迁移创建文件表吗?

1 个答案:

答案 0 :(得分:5)

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

<强>迁移

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

ActiveRecord::ConnectionAdapters::PostgreSQLAdapter

如果您需要执行更多非标准操作,您还可以使用t.column :some_oid, 'blob_oid', :null => false 使用直接SQL创建表。并且,如果您有在迁移之外进行的现有旧架构或SQL更改,请考虑在execute("SQL GOES HERE;")中使用structure.sql(config.active_record.schema_format = :sql选项,然后执行:config/application.rb)。

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

https://github.com/diogob/carrierwave-postgresql/blob/v0.1.0/lib/carrierwave/storage/postgresql_lo.rb

复制了一些修改澄清等

更新:我们可以但不需要在lo_read / lo_write / lo_lseek之前放置一个begin,并且在asse {block}中执行lo_close,因为每个PG documentation“剩下的任何大对象描述符在交易结束时打开将自动关闭。“ (感谢Diogo提供的信息)

rake db:structure:dump

使用模型或基础中的原始连接,而不是 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(见this)。

ActiveRecord::Base.connection.raw_connection正在模型或基础上调用事务,例如(...).transaction(见this)。

ActiveRecord::Base.transaction是您需要传入/设置或从仅执行identifier获取的oid。

其他例子/信息:

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

轻松的方式

只需使用CarrierWavecarrierwave-postgresql