加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby-on-rails – Rails ActiveRecord字符串字段编码与Ruby Stri

发布时间:2020-12-16 21:05:00 所属栏目:百科 来源:网络整理
导读:上下文:从外部源代码转换字符串以保存在数据库中 从gem中,我得到一个包含latin-1编码内容的字符串,并且我希望存储在Rails模型中. r = MyRecord.new(mystring: s)# ...r.save 因为我的PostgreSQL数据库使用UTF-8编码,所以在将字符串字段设置为字符串后保存模
上下文:从外部源代码转换字符串以保存在数据库中

从gem中,我得到一个包含latin-1编码内容的字符串,并且我希望存储在Rails模型中.

r = MyRecord.new(mystring: s)
# ...
r.save

因为我的PostgreSQL数据库使用UTF-8编码,所以在将字符串字段设置为字符串后保存模型会在该字符串包含某些非ASCII字符时导致错误:

ActiveRecord::StatementInvalid: PG::CharacterNotInRepertoire: ERROR:  invalid byte sequence for encoding "UTF8": 0xdf 0x65
...

我可以通过转码字符串轻松解决这个问题:

r = MyRecord.new(mystring: s.encode(Encoding::UTF_8,Encoding::ISO_8859_1))
# ...
r.save

(因为r.encoding返回#<编码:ASCII-8BIT>而不是#<编码:ISO-8859-1>,我是passing the source encoding as the second argument.生成s的gem可能不知道它读取的文件字符串来自latin1编码.)

挑战:避免硬编码目标编码

在我看来,关于数据库的字符串编码的知识不属于我执行此操作的代码部分,因此也不属于代码转换.

我可以向模型的类询问数据库的编码:

MyRecord.connection.encoding

这不会返回Ruby Encoding对象,但会返回包含编码名称的字符串.幸运的是,编码类can be queried with names(和some aliases)查找编码:

Encoding.find 'UTF-8' # returns #<Encoding:UTF-8>,the value of Encoding::UTF_8

遗憾的是,使用了不同的命名约定:MyRecord.connection.encoding返回’UTF8′(无减号),而Encoding.find(…)需要传递’UTF-8′(带减号)或’CP65001’如果我们希望它返回#<编码:UTF-8&gt ;.) Sooooo关闭. 问题:是否有干净和/或推荐的方式 避免目标编码的硬编码,而是动态地确定和使用数据库的编码? 丢弃的想法 我不觉得对MyRecord.connection.encoding的结果进行字符串操作或模式匹配,或者对Encoding.aliases()的内容进行模式匹配比在代码中保留硬编码值更好.

修改Encoding.aliases()的返回值没有任何影响:

Encoding.aliases['UTF8'] = 'UTF-8'
Encoding.find 'UTF8' # ArgumentError: unknown encoding name - UTF8

(无论如何也感觉不对),也没有修改#names的返回值:

Encoding::UTF_8.names.push('UTF8')
Encoding.find 'UTF8'# ArgumentError: unknown encoding name - UTF8

我猜两者都只返回动态生成的集合或底层集合的副本,这是有充分理由的.

解决方法

解决这个问题的最简单,也可以说是最干净的解决方案是不直接调用Encoding.find,但是有一个实用工具方法(可能位于lib / yourapp的模块中),它知道你关心的编码名称差异并退回到所有其他输入的Encoding.find:
module YourApp
  module DatabaseStringEncoding
    def find(name)
      case name
      when 'UTF8'
        Encoding::UTF_8
      ...
      else
        Encoding.find(name)
      end 
    end
  end

这很容易理解和发现(而不是直接修改编码,这对编码的代码的读者来说是不可见的).基于这样的find方法,您可以进一步实现一个方法,该方法使用YourRecord.connection.encoding自动将字符串重新编码为数据库的字符串编码.

我知道让Encoding.find完全按你的意愿去做会更令人兴奋,但我认为这种“笨拙”的做法实际上会更好.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读