Rails 3 - 如何处理PG错误不完整的多字节字符

时间:2012-02-06 21:24:20

标签: ruby-on-rails ruby encoding utf-8

在Rails 3.2应用程序(Ruby 1.9.2)中,我收到以下错误

  

在mobile_users#update中发生了PGError:

     

不完整的多字节字符

这些是Postgres错误我在开发和测试模式下测试时得到类似的SQLIte错误

导致此错误的参数是(故意省略auth令牌)

  * Parameters: {"mobile_user"=>{"quiz_id"=>"1", "auth"=>"xxx", "name"=>"Joaqu\xEDn"}, "action"=>"update", "controller"=>"mobile_users", "id"=>"1", "format"=>"mobile"}

这是作为JSON HTTP Put请求进行的,处理此问题的更新操作如下

  # PUT /mobile_users/1
  # PUT /mobile_users/1.xml
  def update
    @mobile_user = current_mobile_user
    @mobile_user.attributes = params[:mobile_user]

    respond_to do |format|
      if @mobile_user.save
        format.html { redirect_to(@mobile_user, :notice => 'Mobile user was successfully updated.') }
        format.json  { head :ok }
        format.mobile  { head :ok }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.json  { render :json => @mobile_user.errors, :status => :unprocessable_entity }
        format.mobile  { render :json => @mobile_user.errors, :status => :unprocessable_entity }
        format.xml  { render :xml => @mobile_user.errors, :status => :unprocessable_entity }
      end
    end

  end

违规字符串在上面的参数中是“Joaqu \ xEDn”,这是完全有效的。 问题是我需要处理任何语言的所有字符集。

我假设我需要使用iconv库,但为了做到这一点,我需要检测转换为UTF8的字符集,并且我不知道如何做到这一点。

我也在"name"=>"p\xEDa "

的UTF-8中获得了无效的字节序列

2 个答案:

答案 0 :(得分:5)

此:

"Joaqu\xEDn"

"Joaquín"的ISO-8859-1编码版本,因此它不是有效的UTF-8,您的数据库是正确的抱怨它。如果可能,请修复您的移动客户端以在JSON中使用UTF-8;如果你不能这样做那么你可以用这个来修复编码:

params[:mobile_user][:name].force_encoding('iso-8859-1').encode!('utf-8')

在服务器上。将其修复到服务器上的问题是,您必须猜测传入的编码是什么,并且您的猜测可能不正确。没有办法可靠地猜测特定字符串的编码,有rchardet但它不适用于最新版本的Ruby,它似乎已被放弃;您可以修复此gem以使用现代Ruby。还有一些其他的猜测库,但它们似乎都被抛弃了。

默认情况下,JSON文本始终为by definition,Unicode和UTF-8编码:

3.  Encoding

   JSON text SHALL be encoded in Unicode.  The default encoding is
   UTF-8.

任何向您发送不是UTF-8的JSON的客户端都会被IMO破坏,因为几乎所有客户都会认为JSON将是UTF-8。当然,可能有某个编码头指定ISO 8859-1,或者标题可能是UTF-8,即使它是ISO 8859-1。

答案 1 :(得分:4)

我在解析文件时遇到了用户生成数据的相同问题,并以这种方式解决了这个问题:

require 'iconv'
....
line = Iconv.conv('UTF-8//IGNORE', 'UTF-8', line)
#now variable line has valid utf-8 data

您可以尝试覆盖'name'setter,以便它删除非utf8字符:

def name=(name)
  write_attribute(:name, Iconv.conv('UTF-8//IGNORE', 'UTF-8', name))
end