PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Modélisation des grands objets de PostgreSQL dans Rails

Si vous utilisez ActiveRecord fourni avec Rails avec l'un de ses adaptateurs, le seul mappage formel du type de base de données au type Rails ou Ruby qui se produit est généralement défini dans le NATIVE_DATABASE_TYPES constante dans l'adaptateur qui est renvoyée via ses native_database_types méthode. Pour PostgreSQL dans Rails 3.2.x, c'est-à-dire dans ActiveRecord::ConnectionAdapters::PostgreSQLAdapter qui est ici . Ainsi, pour cet adaptateur, le type "binary" dans Rails correspond au type "bytea" dans PG. Pour certains types, vous pouvez remplacer le type de base de données auquel il est mappé à l'aide d'une gemme appelée activerecord-native_db_types_override . Mais, nous voulons utiliser de gros objets, donc...

Migrations

Comme Jim Deville l'a noté dans les commentaires, vous pouvez spécifier la colonne typée personnalisée dans le tableau comme :

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

Si vous avez besoin de faire encore plus de choses non standard, vous pouvez également utiliser un execute("SQL GOES HERE;") pour créer la table à l'aide de SQL direct. Et, si vous avez un schéma hérité existant ou des modifications SQL qui ont été apportées en dehors des migrations, envisagez d'utiliser structure.sql (config.active_record.schema_format = :sql option dans config/application.rb puis faites :rake db:structure:dump ).

Lecture/écriture/vérification de la longueur/suppression d'objets volumineux

Copié avec quelques modifications pour clarifier, etc. depuis :https://github.com/diogob/carrierwave-postgresql/blob/v0.1.0/lib/carrierwave/storage/postgresql_lo.rb :

Mise à jour :nous pouvons mais n'avons pas besoin de mettre un début avant le lo_read/lo_write/lo_lseek et faire lo_close dans le bloc d'assurance parce que par Documentation PG "Tous les descripteurs d'objets volumineux qui restent ouverts à la fin d'une transaction seront automatiquement fermés." (merci à Diogo pour cette info)

    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

Au lieu de connection , utilisez la connexion brute du modèle ou de la base, par ex. ActiveRecord::Base.connection.raw_connection (voir ceci ).

(...).transaction appelle la transaction sur le modèle ou la base, par ex. ActiveRecord::Base.transaction (voir ceci ).

identifier est l'oid que vous devez transmettre/définir ou obtenir simplement en faisant un connection.lo_creat .

Autres exemples/infos :

Ce dernier et quelques réponses ici suggérons que vous souhaitiez peut-être envisager de stocker des fichiers volumineux séparément de la base de données, par ex. afin que vous puissiez utiliser le stockage en nuage. Mais, si seulement stocker les chemins/ID vers des fichiers externes qui ne sont pas géré par la base de données, vous perdez la cohérence ACID (un ou plusieurs enregistrements de base de données peuvent pointer vers un ou plusieurs fichiers qui ne sont pas là ou un ou plusieurs fichiers peuvent exister sans un ou plusieurs enregistrements associés dans la base de données). Un autre argument pour stocker des fichiers sur le système de fichiers est que vous pouvez diffuser des fichiers, mais les grands objets PG stockent les fichiers sur le système de fichiers d'une manière gérée par postgres pour à la fois assurer la cohérence ACID et permettre la diffusion (ce que vous ne pouvez pas faire avec un BLOB normal /Rails de type binaire). Donc, cela dépend simplement; certains trouvent que le stockage dans un stockage séparé en utilisant des références de chemin est une meilleure option, et certains préfèrent la cohérence ACID via les objets volumineux.

La manière simple

Utilisez simplement CarrierWave et carrierwave-postgresql .