こんにちは、hachi8833です。今回はRails 5 Active SupportのString#html_safeを見てみます。
今回のメソッド
- メソッド:
String#html_safeおよび関連メソッド - ディレクトリ配置: rails/activesupport/lib/active_support/core_ext/string/output_safety.rb
条件
- Railsバージョン: 5-0-stable
- Rubyバージョン: 2.3.3
ソースのコメント等は適宜省略します。
html_safeは「安全」であるとマーキングする
今回取り上げるString#html_safeについては、TechRachoの以前の記事『RailsビューのHTMLエスケープは#link_toなどのヘルパーメソッドで解除されることがある』も合わせてお読みいただくことをおすすめします。
html_safeメソッドは対象が安全であることをマーキングし、以後エスケープを行わないようにするメソッドなので、安全であることが間違いなく確認できてから呼び出す必要があります。安全でないオブジェクトを安全にするものではありません。
また、ソースのコメントでも「このメソッドよりもsanitizeメソッドをおすすめする」と記載されています。
output_safety.rbの構成
output_safety.rbでは以下をrequireしています。
require 'erb'
require 'active_support/core_ext/kernel/singleton_class'
output_safety.rbは大きく分けて以下のような構成になっています。html_safeは最後のStringクラスで定義されています。
- ERBクラス内でUtilモジュールを定義
- Objectクラス(
html_safe?を定義) - Numericクラス(
html_safe?を定義) - ActiveSupportモジュールでSafeBufferクラスを定義
- Stringクラス(
html_safeを定義)
class ERB
module Util
...
end
end
class Object
def html_safe?
false
end
end
class Numeric
def html_safe?
true
end
end
module ActiveSupport #:nodoc:
class SafeBuffer < String
class SafeConcatError < StandardError
...
end
...
end
end
class String
def html_safe
ActiveSupport::SafeBuffer.new(self)
end
end
html_safe
html_safeのコードそのものは以下の1行だけであり、ActiveSupport::SafeBufferオブジェクトを作成して返しています。ActiveSupport::SafeBufferクラスは同じファイルにあります。
class String
def html_safe
ActiveSupport::SafeBuffer.new(self)
end
end
ActiveSupport::SafeBufferは同じoutput_safety.rbファイルにあり、以下のメソッドがあります。
インスタンスメソッド
ここがhtml_safeの中心となるメソッド群です。
initializeメソッド[]メソッドsafe_concatメソッドinitialize_copyメソッドclone_emptyメソッドconcatメソッドprependメソッド+メソッド%メソッドhtml_safe?メソッドto_sメソッドto_paramメソッドencode_withメソッド
たとえばconcatメソッドは以下のように式展開のみエスケープして親クラスに渡しています。
def concat(value)
super(html_escape_interpolated_argument(value))
end
プライベートメソッド
- html_escape_interpolated_argumentメソッド
html_escape_interpolated_argumentは、html_safeでない式展開をエスケープします。