ruby-on-rails – Rails ActiveRecord字符串字段编码与Ruby Stri
上下文:从外部源代码转换字符串以保存在数据库中
从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.find 'UTF-8' # returns #<Encoding:UTF-8>,the value of Encoding::UTF_8 遗憾的是,使用了不同的命名约定:MyRecord.connection.encoding返回’UTF8′(无减号),而Encoding.find(…)需要传递’UTF-8′(带减号)或’CP65001’如果我们希望它返回#<编码:UTF-8> ;.) Sooooo关闭. 问题:是否有干净和/或推荐的方式 避免目标编码的硬编码,而是动态地确定和使用数据库的编码? 丢弃的想法 我不觉得对MyRecord.connection.encoding的结果进行字符串操作或模式匹配,或者对 修改Encoding.aliases()的返回值没有任何影响: Encoding.aliases['UTF8'] = 'UTF-8' Encoding.find 'UTF8' # ArgumentError: unknown encoding name - UTF8 (无论如何也感觉不对),也没有修改 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完全按你的意愿去做会更令人兴奋,但我认为这种“笨拙”的做法实际上会更好. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |