dimanche 17 avril 2016

Encoding issues in ActiveModel::Errors

I18n reads from utf-8 formatted yml, and translate will translate from utf-8 to utf-8.

My legacy codes relies heavily on ActiveModel::Errors.full_messages,

E.g.,

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

In view, it uses:

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

The error will be something like:

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

In fact, in full_message function, the real source code is something like:

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

The problem now is: the %{attribute} is utf-8, and the %{message} is not utf-8, so there will be error when calling full_message.

There are several solutions I can think of:

1) alter error messages to utf-8 (there are a lot of other strings that are non-utf-8), so I have to deal with the combination of utf-8 and non-utf-8 everywhere in the source codes and do proper conversion when they come together.

2) find a way to enumerate error messages (similar to full_messages), but with a different implementation. I tried to look into the API of ActiveModel::errors, and could not find internal API so that I can enumerate errors.

3) alter I18n.t default behaviour so it returns non-utf-8.

4) alter ActiveModel::Errors.full_messages so it returns non-utf-8.

The second option is actually the best option, but I am not sure how to enumerate the error messages the same way as full_messages. I couldn't find any public API to return the internal data structure of errors?

The last 2 options require injection to ruby library which I don't know whether it is possible or not.

Please show me some hints. Thanks.

Aucun commentaire:

Enregistrer un commentaire