Pokud používáte ActiveRecord dodávaný s Rails s jedním z jeho adaptérů, jediné formální mapování typu databáze na typ Rails nebo Ruby, ke kterému dochází, je obvykle definováno v NATIVE_DATABASE_TYPES
konstanta v adaptéru, která je vrácena prostřednictvím jeho native_database_types
metoda. Pro PostgreSQL v Rails 3.2.x je to v ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
který je zde
. Takže pro tento adaptér se typ „binary“ v Rails mapuje na typ „bytea“ v PG. U některých typů můžete tento typ databáze, na který se mapuje, přepsat pomocí drahokamu zvaného activerecord-native_db_types_override . Ale chceme používat velké objekty, takže...
Migrace
Jak poznamenal Jim Deville v komentářích, můžete zadat vlastní typovaný sloupec v tabulce jako:
t.column :some_oid, 'blob_oid', :null => false
Pokud potřebujete udělat ještě více, co je nestandardní, můžete také použít execute("SQL GOES HERE;")
k vytvoření tabulky pomocí přímého SQL. A pokud máte existující starší schéma nebo změny SQL, které byly provedeny mimo migrace, zvažte použití structure.sql (config.active_record.schema_format = :sql
možnost v config/application.rb
a pak proveďte:rake db:structure:dump
).
Čtení/zápis/kontrola délky/mazání velkých objektů
Zkopírováno s některými úpravami pro objasnění atd. z:https://github.com/diogob/carrierwave-postgresql/blob/v0.1.0/lib/carrierwave/storage/postgresql_lo.rb :
Aktualizováno :můžeme, ale nemusíme vložit začátek před lo_read/lo_write/lo_lseek a udělat lo_close v bloku secure, protože podle dokumentace PG "Všechny popisovače velkých objektů, které zůstanou otevřené na konci transakce, budou automaticky uzavřeny." (díky Diogo za tuto informaci)
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
Místo connection
, použijte nezpracované spojení z modelu nebo základny, např. ActiveRecord::Base.connection.raw_connection
(viz toto
).
(...).transaction
je volání transakce na modelu nebo bázi, např. ActiveRecord::Base.transaction
(viz toto
).
identifier
je oid, který musíte buď předat/nastavit, nebo jej získat pouhým provedením connection.lo_creat
.
Další příklady/informace:
- 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
Poslední a některé odpovědi zde naznačují, že byste možná chtěli zvážit ukládání velkých souborů odděleně od DB, např. abyste mohli využívat cloudové úložiště. Pokud však pouze ukládáte cesty/ID k externím souborům, které nejsou spravované DB, ztratíte konzistenci ACID (jeden nebo více záznamů DB může ukazovat na jeden nebo více souborů, které tam nejsou, nebo může existovat jeden nebo více souborů, které nemají jeden nebo více přidružených záznamů v databázi). Dalším argumentem pro ukládání souborů v souborovém systému je, že můžete streamovat soubory, ale velký objekt PG ukládá soubory na souborovém systému způsobem spravovaným postgresem, aby byla zajištěna konzistence ACID a umožněno streamování (což nemůžete udělat s normálním BLOBem /Binární typ Rails). Takže záleží jen na tom; někteří považují ukládání v odděleném úložišti pomocí odkazů na cestu za lepší možnost a někteří preferují konzistenci ACID prostřednictvím velkých objektů.
Snadný způsob
Stačí použít CarrierWave a carrierwave-postgresql .