Mustache(gem)の紹介と、思わぬ文字に躓いた話
サーバーサイドエンジニアの福傳です。
Mustacheというgemが便利だったのと、
思いもよらぬ文字に苦しめられたのでまとめてみました。
Mustacheの紹介
自社プロダクトのCarelyでは、フレームワークにRuby on Railsを使っており、その中でmustacheというgemを使っています。
詳しくはREADMEなどに書いているのですが、
>> last_name = "田中"
>> text = "こんにちは、{{name}}さん"
>> Mustache.render(text, { name: last_name })
=> "こんにちは、田中さん"
というように、簡単に変数入りのテンプレートを作成できるというものです。
(コードも追いやすく良い感じです。)
Carelyではメールのテンプレートメッセージを作成するのに使っています。
起こった問題
社内のCSチームが、以下のようなメッセージが作成できないと、報告をくれました。
こんにちは、{{ last_name }}さん
試したところtagの中身が不正というエラーが...
>> text = "こんにちは、{{ last_name }}さん"
>> Mustache.render(text, {last_name: last_name, first_name: first_name})
Mustache::Parser::SyntaxError: Illegal content in tag
Line 1
こんにちは、{{ last_name }}さん
最初はスペースがダメかと思ったのですが、コードを見ると違いそうです。
(半角スペースをスキップしてる)
https://github.com/mustache/mustache/blob/master/lib/mustache/parser.rb#L189
もしや半角スペースではない?
と調べてみると、本当に違うことが発覚
# 文字コードで見比べてみました
# 今回問題の半角スペースぽいもの
>> " ".ord
=> 8239
# 本当の半角スペース
>> " ".ord
=> 32
文字コード8239を調べると、no break space(HTMLの )らしいです。
一旦は「半角スペースを削除してください」と伝えれば良いですが、システム側でフィルタリングしたいですね。
今の実装上、{{ }}
の中身は半角英数字とアンダーバーだけであって欲しいです。
正規表現で取得して置き換えれば出来そうです。
>> text = "こんにちは、{{ last_name }}さん"
# {{}}で囲まれている中で、半角英数字を取得
# matchしたgroupで置き換え
>> fixed_text = text.gsub(/{{\W*(\w+)\W*}}/, "{{\\1}}")
>> Mustache.render(fixed_text, {last_name: last_name})
=> "こんにちは、田中さん"
とりあえず報告をもらった事象は解決できました。
(他のパターンとかエラーハンドリングなど色々ありますがサンプルということで省略します。)
まとめ
当たり前の話ですが、
入力される値は、適切にフィルタリングする必要があると感じた一件でした。
(フィルタリングできないなら適切なエラーハンドリング)
また、gemのコードが読みやすく、原因追求がしやすかったのも良かったです。gem選定の際に気をつけたいですね。
躓いた話になってしまいましたが、mutacheは便利なので、ぜひ使ってみてください!!
補足
Shopifyが作っているliquidというgemでも同じことはできる(はず)ですが、こっちは使ったことないので、そのうち調べたいなあと思っています。