html_safe(HTMLをエンティティ化しないメソッド)と<%=%>の出力関係の理解
Railsでは通常、フォームなどから投げられたデータは自動でHTMLのエンティティ化が行われる。
そのため、このエンティティ化をしないときにhtml_safeメソッドを使用して生のHTMLを取り出してくるが、これについて少しハマった。
今回は俺のいつものエラーでハマったという話ではなく、「なぜこうなるの?」と少し悩み、その際に行った推測と検証からこれについて落とし込んだ内容となる。(かなりおバカな内容なので、プロから見たら鼻で笑われそうな内容)
「入力したフォームから送信した文字列中の改行データを<br />に変換する」というよくある変換をかけようとした際に記事タイトルのような疑問が生まれた。
<%= string.gsub(/(\r\n|\r|\n)/, '<br />') %>
このように出力したときにフォームから送信したデータが、自動でエンティティ化されていることに、今更で恥ずかしながら気づいた。
「あ、Railsって自動でHTMLのエンティティ化されるんや!便利やん!」とか最初は思っていたんだけど、「じゃあエンティティ化外す場合はどないすんねんや」とリファレンスを探した。
そして、以下のようにhtml_safeを使えばできるということがわかった。
<%= string.html_safe %>
で、これが全ての事の発端だった。
この2つのコードを組み合わせる際に、フォームのデータそのものについてはHTMLのエンティティ化を行うけど、改行を<br />に変換した際の<br />については変換しないようにする。その変換を行いたい。
まぁ、今日び色んなサイトがあるわけでその方法のヒントもすぐに出てきた。
それらからコードを組み合わせて、実際のコードをこんな感じで書いたんだ。
<% hoge = html_escape(string) hoge = hoge.gsub(/(\r\n|\r|\n)/, '<br />').html_safe %> <%= hoge %>
html_escapeでstringに入ったHTMLタグを一度エンティティ化して、その上で<br />の変換用のコードを組み合わせる。
で、これで目的の結果は得られた。得られたんだが・・・。
ふとここで俺の頭に疑問点が出てきた。
「あれ?これだと結局、<%= hoge %>で改行を変換した<br />も全部エンティティ化されてしまうんじゃない?」
実は最初の時点で、「あ、Railsって自動でHTMLのエンティティ化されるんや!便利やん!」と思って俺が行った理解は「<%=%>で変換されてるんやな!」という相当ざっくりとしたことだった。
そこにhtml_safeメソッドを入れてみて出力結果を見てみて、これはエンティティ化を解除する関数的な役割を出しているものだと理解していた。
例えば、string.html_safeを変数hogeに入れた場合、変数hogeに入っているものはエンティティ化が解除されたstringであると思っていた。
この場合、変数hogeにはstring.html_safeで生のHTMLが入っていることになる。
これだと仮に<%= hoge %>の前で変数hogeのhtml_safeでエンティティ化を解除したとしても、<%= hoge %>で出てくる結果としては、「<%=%>でエンティティ化された文字列」が出力されるはずだ。
けど、実行の結果は「フォーム内のHTMLはエンティティ化されて」「改行データは生のHTMLの<br />として」の正常な結果が得られている。
それだと当該の変換を行った際に、俺がした理解に矛盾が生じてくる。
このままうやむやにするとなんか気持ち悪いので、検証を行った。
<% string = 'あいうえお<a href="#">HTML</a>かきくけこ' hoge = { 'plain' => string, 'html_safe' => string.html_safe, } #raise hoge.inspect %> <p><%= hoge['plain'] %></p> <p><%= hoge['html_safe'] %></p>
検証を行うに当たり、以上のようなコードを作成。
hoge[‘plain’]は変数stringをそのまま代入したもの、hoge[‘html_safe’]はエンティティ化を解除するものである。
コメントアウトされているraiseのコメントを外して、実行してみると以下のような結果が得られた。
上記の通り、hoge[‘plain’]とhoge[‘html_safe’]には全く差異がない。
そしてraiseを再びコメントアウトして、今度は<%= hoge[‘plain’] %>と<%= hoge[‘html_safe’] %>の結果を表示してみる。
このような結果となった。
ということはつまり、html_safeメソッドは付けたその時点での単純な変換は行われていないということになる。
なるほどね。
これから合理的な理解を得るに、html_safeメソッドは<%= %>内で有効な、プロパティのような働きをするメソッドであるということ。
なので、「html_safeメソッドとは単純に文字列のHTMLをエンティティ化しないように変換するメソッド」という理解ではなく、「html_safeメソッドを辿らせておくことで、<%=%>で出力する際に文字列をエンティティ化しないようにする」という理解を得たほうが正しい。
多分、他の出力に関わるメソッドも同じようになってんだろう。
こういうところがRuby on Railsのアクとクセの強いところなんだよなぁ・・・。
まぁ、今回の検証と理解はいいお勉強内容となった。