ActiveModel::Errors 中的编码问题

Encoding issues in ActiveModel::Errors

I18n 从 utf-8 格式的 yml 中读取,translate 将从 utf-8 转换为 utf-8。

我的遗留代码严重依赖于 ActiveModel::Errors.full_messages,

例如,

# note: the message is not utf-8 encoding
validates_length_of :title,:maximum => 2,:message => 'abc'.encode("shift_jis")

在视图中,它使用:

item.errors.full_messages.each do |msg|
end

错误将类似于:

I18n.t(:title) + " " + 'abc'

其实在full_message函数中,真正的源代码是这样的:

def full_message(attribute, message)
  return message if attribute == :base
  attr_name = attribute.to_s.tr('.', '_').humanize
  attr_name = @base.class.human_attribute_name(attribute, default: attr_name)
  I18n.t(:"errors.format", {
    default:  "%{attribute} %{message}",
    attribute: attr_name,
    message:   message
  })
end

现在的问题是:%{attribute}是utf-8,%{message}不是utf-8,所以调用full_message会报错。

我能想到的解决方案有几种:

1) 将错误消息更改为 utf-8(还有很多其他非 utf-8 的字符串),因此我必须到处处理 utf-8 和非 utf-8 的组合在源代码中,并在它们组合在一起时进行适当的转换。

2) 找到一种枚举错误消息的方法(类似于full_messages),但实现方式不同。我试图查看 ActiveModel::errors 的 API,但找不到内部 API 以便我可以列举错误。

3) 改变 I18n.t 默认行为,使其 return 成为非 utf-8。

4) 改变 ActiveModel::Errors.full_messages 所以它 return 是非 utf-8.

第二个选项实际上是最好的选项,但我不确定如何像 full_messages 一样枚举错误消息。我找不到任何 public API 到 return 错误的内部数据结构?

最后两个选项需要注入 ruby 库,我不知道是否可行。

请给我一些提示。谢谢。

您可以更改 ruby(和 rails)中几乎所有内容的行为。

只需在 config/initializers 中创建一个新的初始化文件,内容如下:

#monkeypatch_i18n.rb
(i don't know the exact path of active_model/errors.full_messages)
module ActiveModel
  module Errors
    def full_messages
      #new logic
    end
  end
end

这会覆盖默认方法。

此致, 卷麻.

编辑: 一个更干净的解决方案可能是:

#lib/monkey_patch_i18n.rb
module ActiveModel
      module Errors
        def full_messages
          #new logic
        end
      end
    end

#config/initializers/init_i18n.rb
require "#{Rails.root}/lib/monkey_patch_i18n.rb"