Ако използвате ActiveRecord, който идва с Rails с един от неговите адаптери, единственото формално съпоставяне на тип база данни с тип Rails или Ruby, което се случва, обикновено се дефинира в NATIVE_DATABASE_TYPES
константа в адаптера, която се връща чрез неговите native_database_types
метод. За PostgreSQL в Rails 3.2.x, това е в ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
което е тук
. И така, за този адаптер типът "двоичен" в Rails се преобразува в типа "bytea" в PG. За някои типове можете да замените този тип база данни, към който той се присвоява, като използвате gem, наречен activerecord-native_db_types_override . Но искаме да използваме големи обекти, така че...
Миграции
Както Джим Девил отбеляза в коментарите, можете да посочите персонализираната колона в таблицата като:
t.column :some_oid, 'blob_oid', :null => false
Ако трябва да направите дори повече, което е нестандартно, можете също да използвате execute("SQL GOES HERE;")
за създаване на таблицата с помощта на прав SQL. И ако имате съществуваща наследена схема или промени в SQL, които са направени извън миграциите, обмислете използването на structure.sql (config.active_record.schema_format = :sql
опция в config/application.rb
и след това направете:rake db:structure:dump
).
Големи обекти Четене/Запис/Проверка на дължина/Изтриване
Копирано с някои модификации за изясняване и т.н. от:https://github.com/diogob/carrierwave-postgresql/blob/v0.1.0/lib/carrierwave/storage/postgresql_lo.rb :
Актуализирано :можем, но не е необходимо да поставяме начало преди lo_read/lo_write/lo_lseek и да правим lo_close в блока за осигуряване, защото според PG документация „Всички големи обектни дескриптори, които остават отворени в края на транзакцията, ще бъдат затворени автоматично.“ (благодарение на Диого за тази информация)
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
Вместо connection
, използвайте необработената връзка от модела или основата, напр. ActiveRecord::Base.connection.raw_connection
(вижте това
).
(...).transaction
извиква транзакция на модел или база, напр. ActiveRecord::Base.transaction
(вижте това
).
identifier
е oid, който или трябва да подадете/настроите, или да получите от просто извършване на connection.lo_creat
.
Други примери/информация:
- 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
Последното и някои отговори тук предлагаме да помислите за съхранение на големи файлове отделно от DB, напр. така че да можете да използвате облачно хранилище. Но ако съхранявате само пътищата/идентификаторите към външни файлове, които не са управлявани от DB, вие губите ACID последователност (един или повече DB записи може да сочат към един или повече файлове, които не са там, или един или повече файлове може да съществуват, които нямат един или повече свързани записи в базата данни). Друг аргумент за съхраняване на файлове във файловата система е, че можете да предавате файлове поточно, но големият обект на PG съхранява файлове във файловата система по начин, управляван от postgres, за да осигури съвместимост на ACID и да позволи поточно предаване (което не можете да направите с нормален BLOB /Rails двоичен тип). Така че просто зависи; някои смятат, че съхраняването в отделно хранилище, използвайки препратки към пътя, е по-добър вариант, а някои предпочитат ACID последователност чрез големи обекти.
Лесният начин
Просто използвайте CarrierWave и carrierwave-postgresql .