PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Modelando os grandes objetos do PostgreSQL no Rails


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:

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 .