Jeśli używasz ActiveRecord, który jest dostarczany z Railsem z jednym z jego adapterów, jedyne formalne mapowanie typu bazy danych na typ Rails lub Ruby, które ma miejsce, jest zazwyczaj zdefiniowane w NATIVE_DATABASE_TYPES
stała w adapterze, która jest zwracana przez jego native_database_types
metoda. Dla PostgreSQL w Rails 3.2.x, czyli w ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
czyli tutaj
. Tak więc dla tego adaptera typ "binarny" w Railsach jest odwzorowany na typ "bytea" w PG. W przypadku niektórych typów możesz zastąpić ten typ bazy danych, do którego mapuje, używając klejnotu o nazwie activerecord-native_db_types_override . Ale chcemy używać dużych obiektów, więc...
Migracje
Jak zauważył Jim Deville w komentarzach, możesz określić niestandardową kolumnę w tabeli, taką jak:
t.column :some_oid, 'blob_oid', :null => false
Jeśli potrzebujesz zrobić jeszcze więcej, co jest niestandardowe, możesz również użyć execute("SQL GOES HERE;")
utworzyć tabelę za pomocą prostego SQL. A jeśli masz istniejący starszy schemat lub zmiany SQL, które zostały wprowadzone poza migracjami, rozważ użycie pliku structure.sql (config.active_record.schema_format = :sql
opcja w config/application.rb
a następnie wykonaj:rake db:structure:dump
).
Odczyt/zapis/sprawdzenie długości/usunięcie dużych obiektów
Skopiowano z pewnymi modyfikacjami w celu wyjaśnienia itp. z:https://github.com/diogob/carrierwave-postgresql/blob/v0.1.0/lib/carrierwave/storage/postgresql_lo.rb :
Zaktualizowano :możemy, ale nie musimy, umieścić początek przed lo_read/lo_write/lo_lseek i wykonać lo_close w bloku zapewnienia, ponieważ na Dokumentacja PG „Wszelkie deskryptory dużych obiektów, które pozostają otwarte po zakończeniu transakcji, zostaną automatycznie zamknięte”. (dzięki Diogo za te informacje)
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
Zamiast connection
, użyj surowego połączenia z modelu lub bazy, np. ActiveRecord::Base.connection.raw_connection
(zobacz to
).
(...).transaction
wywołuje transakcję na modelu lub bazie, np. ActiveRecord::Base.transaction
(zobacz to
).
identifier
jest oidem, który musisz przekazać/ustawić lub uzyskać po prostu wykonując connection.lo_creat
.
Inne przykłady/informacje:
- http://rubydoc.info/github/nedforce/devcms-core/ Plik Db
- https://github.com/nedforce/devcms-core
- http://my.safaribooksonline.com/ książka/web-development/ruby/9780596510329/database/largebinary_objects
Te ostatnie i niektóre odpowiedzi tutaj zasugeruj, że warto rozważyć przechowywanie dużych plików oddzielnie od bazy danych, np. dzięki czemu możesz korzystać z pamięci w chmurze. Ale jeśli tylko przechowujesz ścieżki/identyfikatory do zewnętrznych plików, które nie zarządzane przez bazę danych, tracisz spójność ACID (jeden lub więcej rekordów bazy danych może wskazywać na jeden lub więcej plików, których tam nie ma lub może istnieć jeden lub więcej plików, które nie mają jednego lub więcej skojarzonych rekordów w bazie danych). Innym argumentem przemawiającym za przechowywaniem plików w systemie plików jest możliwość strumieniowego przesyłania plików, ale duży obiekt PG przechowuje pliki w systemie plików w sposób zarządzany przez postgres, aby zapewnić spójność ACID i umożliwić przesyłanie strumieniowe (czego nie można zrobić z normalnym BLOBem /Rails typu binarnego). Więc to po prostu zależy; niektórzy uważają przechowywanie w oddzielnej pamięci za pomocą odniesień do ścieżki za lepszą opcję, a niektórzy wolą spójność ACID za pośrednictwem dużych obiektów.
Łatwy sposób
Po prostu użyj CarrierWave i carrierwave-postgresql .