2017-09-05 44 views
1

私はRailsのcontent_tagヘルパーを使用してHTMLコードのブロックを構築しています。私が今直面している課題は、content_tagによって生成されたHTML要素と配列のHTML文字列を結合することです。safe_joinとcontent_tagでhtml_safeを置き換える方法

RuboCop Rails/OutputSafetyを参照してください。例えば

:私は以下のようにhtml_safeのアプローチを使用している場合

options = ["<li>Three</li>", "<li>Four</li>", "<li>Five</li>"] 

# This is code to generate blocks of HTML 
out = [] 
out << content_tag(:ul, 
    content_tag(:li, "One") + 
    content_tag(:li, "Two") + 
    options.join(''), 
:class => ["class_1", "class_2"]) 
safe_join(out) 

# Expect result should be like 
<ul class="class_1 class_2"> 
    <li>One</li> 
    <li>Two</li> 
    <li>Three</li> 
    <li>Four</li> 
    <li>Five</li> 
</ul> 

# Actual result 
<ul class="class_1 class_2"> 
    <li>One</li> 
    <li>Two</li> 
    "<li>Three</li><li>Four</li><li>Five</li>" 
</ul> 

しかし、それは動作します。

%{<ul> 
    <li>One</li> 
    <li>Two</li> 
    #{options.join('')} 
</ul> 
}.html_safe 

何を変更する必要がありますか?

# New apporach 
options = ["Three", "Four", "Five"] 
out = [] 
out << content_tag(:ul, 
    content_tag(:li, "One") + 
    content_tag(:li, "Two") + 
    options.collect do |option| 
     content_tag(:li, "#{option[0]}") 
    end.join(""), 
:class => ["class_1", "class_2"]) 
safe_join(out) 

# New approach result 
<ul class="class_1 class_2"> 
    <li>One</li> 
    <li>Two</li> 
    "<li>Three</li><li>Four</li><li>Five</li>" 
</ul> 
+0

safe_joinとcontent_tagヘルパーでhtml_safeに代わる代替より安全な方法を探している人のために。完全で記述的な解決法の答えを見てください。 – zihaow

答えて

3

問題は、optionsアレイから出力される安全でない文字列を出力に連結していることです。これは、あなたが安全であることを全体の出力のためのhtml_safe方法を使用する必要がある唯一の場所である:

out << content_tag(:ul, 
    content_tag(:li, "One") + 
    content_tag(:li, "Two") + 
    options.join('').html_safe, 
:class => ["class_1", "class_2"]) 

編集

すべてsafe_join方法の第一は、それがするだけでなく、html_safe方法のように動作しません。結合された文字列をhtml_safeにします。また、有害なコンテンツを避けるために、結合された文字列がhtml_safeでない場合、htmlをエスケープします。彼らはすでにhtml_safeたので、safe_join方法は、out配列内の文字列で、まったく何もしませんでしたあなたの場合は

https://apidock.com/rails/ActionView/Helpers/OutputSafetyHelper/safe_join

result = content_tag(:ul, 
      content_tag(:li, "One") + 
      content_tag(:li, "Two") + 
      options.join(''), 
      :class => ["class_1", "class_2"]) 

result.html_safe? # => true 

問題の原因は、あなたが危険なものと安全な文字列を連結していることである:

content_tag(:li, "Two") + options.join('') 

content_tag(:li, "Two").html_safe? # => true 
options.join('').html_safe?  # => false 

その瞬間、それは安全ではありませんでしたので、options.join('')は、HTMLエスケープされました。例を参照してください:

# html tags in the second string are escaped, since it is not safe 
"<li>One</li>".html_safe + "<li>Two</li>" # => "<li>One</li>&lt;li&gt;Two&lt;/li&gt;" 

# nothing has been escaped, since everything is safe 
"<li>One</li>".html_safe + "<li>Two</li>".html_safe # => "<li>One</li><li>Two</li>" 

ので、順番に期待を取得する結果の2つの条件を満たしている必要があります。

  1. safe_join方法はhtml_safe文字列の配列を取る必要があります。それらがhtml_safeでない場合、すべてのhtmlタグがエスケープされます。
  2. 安全でない文字列を安全な文字列に連結しないでください。そうでない場合、最初の文字列はエスケープされます。

ご覧のとおり、2番目の条件を満たしていません。新しいアプローチについて

提案が

.join("")方法は、配列が安全な文字列が含まれていても、結果の文字列が危険な状態になります。safe_joinを使用します。

content_tag(:li, "One") + 
    content_tag(:li, "Two") + 
    safe_join(
    options.collect do |option| 
     content_tag(:li, option) 
    end 
    ) 
+0

はい、私はhtml_safeアプローチを行い、うまくいきました。私はhtml_safeを使用せずに達成するための代替方法を見つけようとしています。そのため、私はsafe_joinアプローチを行っています(参考:http://rubocop.readthedocs.io/en/latest/cops_rails/#railsoutputsafety) – zihaow

+0

私はさらに説明 – chumakoff

+0

説明したことが本当に役に立ちます。私はcontent_tagは常にHTML安全な文字列を生成するのだろうかと思います。しかし、content_tagを[collect .. end]スコープの中にラップすると。 HTML安全文字列を生成しません。何か案は?私の新しいアプローチを見てください。 @chumakoff – zihaow

関連する問題