Haml 5でJSON.parseエラーが起きるときの対処

Haml 4 系から Haml 5 へのアップグレードで入った変更点のひとつである HTML エスケープまわり変更の影響で、既存コードで JSON.parse エラーが起きるときの対処については以下の k0kubun さんの PR が参考になる。

github.com

raw でもエラーを起こさない形にはできるがセキュリティ的に怖さがあるメソッドはできる限り使いたくない。こういった場合は data attribute を使うことで対処するのが正攻法。勉強になる。

RuboCop のドキュメントっぽく bad / good を使って、上記 PR でのコードを例に変更方法を示すとこうなる。

bad

    = javascript_include_tag "rails_admin/rails_admin.js"
     -# Initialize JS simple i18n
     :javascript
-      RailsAdmin.I18n.init('#{I18n.locale}', JSON.parse("#{j I18n.t("admin.js").to_json}"))
+      RailsAdmin.I18n.init('#{I18n.locale}', JSON.parse("#{j(raw I18n.t("admin.js").to_json)}"))
   %body.rails_admin
     #loading.label.label-warning{style: 'display:none; position:fixed; right:20px; bottom:20px; z-index:100000'}= t('admin.loading')
     %nav.navbar.navbar-default.navbar-fixed-top

good

    = csrf_meta_tag
     = stylesheet_link_tag "rails_admin/rails_admin.css", media: :all
     = javascript_include_tag "rails_admin/rails_admin.js"
+  %body.rails_admin
+    #admin-js{:'data-i18n-options' => I18n.t("admin.js").to_json}
     -# Initialize JS simple i18n
     :javascript
-      RailsAdmin.I18n.init('#{I18n.locale}', JSON.parse("#{j I18n.t("admin.js").to_json}"))
-  %body.rails_admin
+      RailsAdmin.I18n.init('#{I18n.locale}', document.getElementById("admin-js").dataset.i18nOptions);
     #loading.label.label-warning{style: 'display:none; position:fixed; right:20px; bottom:20px; z-index:100000'}= t('admin.loading')
     %nav.navbar.navbar-default.navbar-fixed-top
       = render "layouts/rails_admin/navigation"