Se estiver usando o ActiveRecord que vem com o Rails com um de seus adaptadores, o único mapeamento formal do tipo de banco de dados para o tipo Rails ou Ruby que acontece normalmente é definido no
NATIVE_DATABASE_TYPES
constante no adaptador que é retornado por meio de seu native_database_types
método. Para PostgreSQL no Rails 3.2.x, que está em ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
que é aqui
. Portanto, para esse adaptador, o tipo "binário" no Rails é mapeado para o tipo "bytea" no PG. Para alguns tipos, você pode substituir esse tipo de banco de dados que ele mapeia usando uma gem chamada activerecord-native_db_types_override . Mas, queremos usar objetos grandes, então... Migrações
Como Jim Deville observou nos comentários, você pode especificar a coluna de tipo personalizado na tabela como:
t.column :some_oid, 'blob_oid', :null => false
Se você precisar fazer ainda mais que não seja padrão, você também pode usar um
execute("SQL GOES HERE;")
para criar a tabela usando SQL direto. E, se você tiver um esquema legado existente ou alterações SQL que foram feitas fora das migrações, considere o uso de structure.sql (config.active_record.schema_format = :sql
opção em config/application.rb
e então faça:rake db:structure:dump
). Objetos grandes leem/gravam/verificam comprimento/excluem
Copiado com algumas modificações para esclarecer, etc. de:https://github.com/diogob/carrierwave-postgresql/blob/v0.1.0/lib/carrierwave/storage/postgresql_lo.rb :
Atualizado :podemos, mas não precisamos, colocar um começo antes de lo_read/lo_write/lo_lseek e fazer lo_close no bloco de garantia porque por Documentação do PG "Qualquer descritor de objeto grande que permaneça aberto no final de uma transação será fechado automaticamente." (obrigado ao Diogo por essa informação)
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
Em vez de
connection
, use a conexão bruta do modelo ou base, por exemplo. ActiveRecord::Base.connection.raw_connection
(consulte este
). (...).transaction
está chamando a transação no modelo ou base, por exemplo ActiveRecord::Base.transaction
(veja este
). identifier
é o oid que você precisa passar / definir ou obter apenas fazendo um connection.lo_creat
. Outros exemplos/informações:
- http://rubydoc.info/github/nedforce/devcms-core/ DbFile
- https://github.com/nedforce/devcms-core
- http://my.safaribooksonline.com/ book/web-development/ruby/9780596510329/database/largebinary_objects
O último e algumas respostas aqui sugiro que você considere o armazenamento de arquivos grandes separados do banco de dados, por exemplo, para que você possa usar o armazenamento em nuvem. Mas, se apenas armazenar os caminhos/IDs para arquivos externos que não gerenciado pelo banco de dados, você perde a consistência ACID (um ou mais registros do banco de dados podem apontar para um ou mais arquivos que não estão lá ou podem existir um ou mais arquivos que não têm um ou mais registros associados no banco de dados). Outro argumento para armazenar arquivos no sistema de arquivos é que você pode transmitir arquivos, mas o objeto grande PG armazena arquivos no sistema de arquivos de uma maneira gerenciada pelo postgres para garantir a consistência ACID e permitir o streaming (o que você não pode fazer com um BLOB normal /Rails tipo binário). Então, só depende; alguns acham que armazenar em armazenamento separado usando referências de caminho é uma opção melhor, e alguns preferem a consistência ACID por meio de objetos grandes.
A maneira mais fácil
Basta usar CarrierWave e carrierwave-postgresql .