Проблема с кодировкой в Sprockets 3 при работе с HTML файлами
Я не так давно обновил один из проектов до Rails 4.2 и заметил интересный эффект: кодировка обработанных html файлов в ассетах меняется на ISO-8859–1.Данная проблема актуальна для Sprockets 3.0.0 и 3.0.1.Проблема нашлась в EncodingUtils#detect_html:
#… module Sprockets # Internal: HTTP transport encoding and charset detecting related functions. # Mixed into Environment. module EncodingUtils extend self #… # Public: Detect charset from HTML document. Defaults to ISO-8859–1. # # str — String. # # Returns a encoded String. def detect_html (str) str = detect_unicode_bom (str) # Attempt Charlock detection if str.encoding == Encoding: BINARY charlock_detect (str) end # Fallback to ISO-8859–1 if str.encoding == Encoding: BINARY str.force_encoding (Encoding: ISO_8859_1) end str end CHARSET_DETECT[: html] = method (: detect_html) end end При загрузке файла Sprockets пытается определить стандарт юникода, почистить строку от BOM и вернуть в нужной кодировке. В случае с html, если не удалось определить кодировку на этом этапе, то пытаемся дать это сделать charlock_holmes (если он установлен), иначе принудительно конвертируем в ISO-8859–1.
Проблема в том, что BOM не является обязательным для UTF-8 и поэтому практически все редакторы сохраняют файлы в UTF-8 без BOM. А это значит, что метод `detect_unicode_bom` по большому счету является бесполезным и html файлы в ассетах всегда будут преобразованы в ISO-8859–1.
Решить проблему можно следующими способами:
1. Переопределить Mime Type для text/html в инициализаторе:
Rails.application.assets.register_mime_type ('text/html', extensions: '.html', charset: : default) 2. Установить charlock_holmes.3. Обновиться до версии 3.0.2, где поведение по умолчанию изменено с ISO-8859–1 на Encoding.default_external (pull request)