二进制文件附件"无法识别的格式或#34;对于postgresql和rails 4

时间:2014-10-03 11:34:07

标签: ruby-on-rails ruby postgresql nginx centos

我目前在使用ruby on rails(4.1.1)在postresql(9.3)上将文件存储为二进制blob时遇到问题。从我保存的登台/生产服务器打开文件时,我得到了

unrecognizable format

表示文件(可能)已损坏。我确认使用textedit,从生产中下载的文件显示" x89504e470d0a1a0a0000000d494844520000010b000001c00800000000901112f9000000097048597300000c4e00000c4e017f778c23000003186943435050686f746f736 ..." (首先我认为它是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

这是数据文件对象的模式

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 个答案:

答案 0 :(得分:3)

您正在查看的结果是由PostgreSQL 9.0或更高版本生成的类型为bytea的值的十六进制字符串,当bytea_output参数设置为hex时会发生这种情况。

与9.0之前的libpq链接的SQL应用程序将无法正确解码这些内容,并且基本上会像问题中所示那样逐字回流十六进制字符串。据推测,您的生产环境和开发环境之间的差异是libpq的版本。

作为一种解决方法,在升级之前,您可以在方便的时候在几个可能的级别强制bytea_ouput使用其旧的默认值escape

  • 表示整个群集,已在postgresql.conf
  • 中配置
  • 适用于ALTER DATABASE dbname SET bytea_output to 'escape';
  • 的一个数据库
  • 针对特定用户:ALTER USER username SET bytea_output to 'escape';
  • 用于SQL会话(非持久性):SET bytea_output TO 'escape';