Вставка двоичного файла "нераспознаваемый формат" для postresql и рельсов 4

В настоящее время у меня проблема с хранением файлов в виде двоичных blobs на postresql (9.3) с ruby on rails (4.1.1). При открытии файла с сервера постановки/производства, который я сохранил, я получаю

unrecognizable format

что означает, что файл (возможно) поврежден. Я подтвердил, что с textedit, где файл, загруженный с производства, отображает "x89504e470d0a1a0a0000000d494844520000010b000001c00800000000901112f9000000097048597300000c4e00000c4e017f778c2300000c4e017f778c23000003186943435050686f746f736..." (сначала я думал, что это кодировка base64), когда он должен отображать обычный заголовок PNG тестового файла "... PNG... IHDR.. ".

Как ни странно, проблема возникает только в производственной среде (Centos6 + Passenger + NginX), в то время как среда разработки (MacOS) отлично работает. Более того, я не знаю, является ли это проблемой Postgres, так как после того, как я попытаюсь восстановить производственный дамп на моей машине разработки, файлы, которые я загрузил в производство, открылись просто отлично! Вот код, который создает объект data_file (тот, который содержит двоичное содержимое):

def create
 authorize! :create, :data_file # cancan authorization
 file = params[:file]
 @data_file = DataFile.new(name: file.original_filename,
 size: file.size,
 contents: file.read,
 content_type: file.content_type # + some additional params)
 authorize! :update, @data_file # other cancan authorization
 if @data_file.save
 render("data_files/show", formats: :json)
 else
 render json: {errors: @data_file.errors}, status: 403
 end
end

и вот код, который отображает файл

def show
 @data_file = DataFile.find(params[:id])
 authorize! :show, @data_file
 send_data @data_file.contents, :disposition => 'attachment', :filename => @data_file.name
end

здесь приведена схема объекта datafile

create_table "data_files", force: true do |t|
 t.string "name"
 t.integer "user_id"
 t.integer "project_id"

 t.string "size"
 t.datetime "created_at"
 t.datetime "updated_at"
 t.binary "contents"
 t.integer "content_type"
 t.string "valid_from"
 t.string "valid_until"
 t.datetime "formatted_valid_until"
 t.datetime "formatted_valid_from"
end

Было бы здорово, если бы кто-то помог мне в этом вопросе. Странно, что программа ведет себя по-разному в средах, которые кажутся одинаковыми.

Заранее спасибо!

1 ответ

Результат, который вы смотрите, представляет собой шестнадцатеричную строку значения типа bytea сгенерированного PostgreSQL 9.0 или выше, что происходит, когда параметр bytea_output установлен в hex.

Приложение SQL, связанное с pre-9.0 libpq, не будет надлежащим образом декодировать это содержимое и в основном сгладить шестнадцатеричную строку дословно, как показано в вопросе. Предположительно, разница между вашей производственной средой и средой dev - это версия libpq.

В качестве обходного пути, до обновления, вы можете заставить bytea_ouput его более старое значение по умолчанию, escape на нескольких возможных уровнях, в удобное для вас время:

  • для всего кластера, настроенного в postgresql.conf
  • для одной базы данных с ALTER DATABASE dbname SET bytea_output to 'escape';
  • для конкретного пользователя: ALTER USER username SET bytea_output to 'escape'; пользователя ALTER USER username SET bytea_output to 'escape';
  • для сеанса SQL (непостоянный): SET bytea_output TO 'escape';

licensed under cc by-sa 3.0 with attribution.