sql >> Base de Datos >  >> RDS >> PostgreSQL

Modelado de objetos grandes de PostgreSQL en Rails

Si usa ActiveRecord que viene con Rails con uno de sus adaptadores, la única asignación formal del tipo de base de datos al tipo Rails o Ruby que ocurre generalmente se define en NATIVE_DATABASE_TYPES constante en el adaptador que se devuelve a través de sus native_database_types método. Para PostgreSQL en Rails 3.2.x, eso está en ActiveRecord::ConnectionAdapters::PostgreSQLAdapter que está aquí . Entonces, para ese adaptador, el tipo "binario" en Rails se asigna al tipo "bytea" en PG. Para algunos tipos, puede anular ese tipo de base de datos al que se asigna usando una gema llamada activerecord-native_db_types_override . Pero queremos usar objetos grandes, así que...

Migraciones

Como señaló Jim Deville en los comentarios, puede especificar la columna escrita personalizada en la tabla como:

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

Si necesita hacer aún más que no sea estándar, también puede usar execute("SQL GOES HERE;") para crear la tabla usando SQL directo. Y, si tiene un esquema heredado existente o cambios de SQL que se han realizado fuera de las migraciones, considere usar structure.sql (config.active_record.schema_format = :sql opción en config/application.rb y luego haz:rake db:structure:dump ).

Objetos grandes Leer/Escribir/Comprobar longitud/Eliminar

Copiado con algunas modificaciones para aclarar, etc. de:https://github.com/diogob/carrierwave-postgresql/blob/v0.1.0/lib/carrierwave/storage/postgresql_lo.rb :

Actualizado :podemos, pero no es necesario, poner un comienzo antes de lo_read/lo_write/lo_lseek y hacer lo_close en el bloque de garantía porque por Documentación de PG "Cualquier descriptor de objeto grande que permanezca abierto al final de una transacción se cerrará automáticamente". (gracias a Diogo por esa información)

    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

En lugar de connection , use la conexión sin procesar del modelo o la base, p. ActiveRecord::Base.connection.raw_connection (ver esto ).

(...).transaction está llamando a la transacción en el modelo o la base, p. ActiveRecord::Base.transaction (ver esto ).

identifier es el oid que necesita pasar/establecer u obtener simplemente haciendo connection.lo_creat .

Otros ejemplos/información:

Este último y algunas respuestas -mb-en-una-base-de-datos">aquí sugiera que es posible que desee considerar el almacenamiento de archivos grandes separados de la base de datos, p. para que pueda usar el almacenamiento en la nube. Pero, si solo almacena las rutas/ID de archivos externos que no administrado por la base de datos, pierde la consistencia ACID (uno o más registros de la base de datos podrían apuntar a uno o más archivos que no están allí o uno o más archivos podrían existir que no tienen uno o más registros asociados en la base de datos). Otro argumento para almacenar archivos en el sistema de archivos es que puede transmitir archivos, pero el objeto grande PG almacena archivos en el sistema de archivos de una manera administrada por postgres para garantizar la coherencia ACID y permitir la transmisión (lo que no puede hacer con un BLOB normal /Rails tipo binario). Entonces, solo depende; algunos encuentran que el almacenamiento en almacenamiento separado usando referencias de ruta es una mejor opción, y algunos prefieren la consistencia ACID a través de objetos grandes.

La Manera Fácil

Simplemente use CarrierWave y carrierwave-postgresql .