RailsのViewテンプレート内でself.output_buffer.gsub!するとCould not concatenate to the buffer because it is not html safe.って勢いよく怒られるので回避する。

RailsのViewテンプレート内でself.output_buffer.gsub!するとCould not concatenate to the buffer because it is not html safe.って勢いよく怒られるので回避する。

おつかれさまです。8月から無職です(どうしよう)。

さて

様々な名状しがたい事情により、テンプレート内で上部の文字列を置換したいと思いました。

<h1>メッセージ</h1>
<p>:message:</p>
<% self.output_buffer.gsub!(':message:', @message.content) %>
<footer><%= @message.author %></footer>

すると

ActiveSupport::SafeBuffer::SafeConcatError
# Could not concatenate to the buffer because it is not html safe.

いただきました。

これはActionView::OutputBufferのスーパークラスであるところのActiveSupport::SafeBufferの機能で、特定のメソッドを介した変更は!html_safe?化させ、!html_safe?に対してさらにsafe_concatで文字列を追加していこうとすると例外が出るというやつです。

    UNSAFE_STRING_METHODS = %w(
      capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
      slice squeeze strip sub succ swapcase tr tr_s upcase
    )

safe_concatを避ける

というわけで、gsub!後にsafe_concatが呼ばれなければこの例外は生じないので、

<h1>メッセージ</h1>
<p>:message:</p>
<footer><%= @message.author %></footer>
<% self.output_buffer.gsub!(':message:', @message.content) %>

最終行に持っていくと怒られません。

UNSAFE_STRING_METHODSを避ける

あるいはUNSAFE_STRING_METHODSを回避するために

class String
  alias :gsub_not_safety! :gsub!
end

して

<h1>メッセージ</h1>
<p>:message:</p>
<% self.output_buffer.gsub_not_safety!(':message:', @message.content) %>
<footer><%= @message.author %></footer>

HTML素通し

いずれもhtml_safeという概念を完全に無視っているので、HTMLエスケープなどはされず、全部素通しです。さすがにこれはよくなさそうだなぁと思ったので、置換できるgemにまとめました。

https://github.com/mmmpa/kaizan