safe_join 和 content_tag 方法替换 html_safe
safe_join and content_tag approach to replace html_safe
我正在使用 Rails' content_tag
助手构建一个 HTML 代码块。我现在面临的挑战是从一个数组中加入 HTML 个字符串,其中 HTML 个元素由 content_tag
.
生成
RuboCop Rails/OutputSafety 参考。
例如:
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>
但是,如果我使用下面的 html_safe 方法,它将起作用。
%{<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>
问题是您将输出与来自 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 转义。
https://apidock.com/rails/ActionView/Helpers/OutputSafetyHelper/safe_join
在您的例子中,safe_join
方法根本没有对 out
数组中的字符串执行任何操作,因为它们已经是 html_safe。
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><li>Two</li>"
# 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 个条件:
safe_join
方法必须采用 html_safe 字符串数组。如果它们不是 html_safe,所有 html 标签都将被转义。
- 不要将安全字符串与不安全字符串连接起来,否则不安全字符串将被转义。
如您所见,您没有满足第二个条件。
关于新方法的建议
.join("")
方法使结果字符串不安全,即使数组包含安全字符串也是如此。使用 safe_join
:
content_tag(:li, "One") +
content_tag(:li, "Two") +
safe_join(
options.collect do |option|
content_tag(:li, option)
end
)
我正在使用 Rails' content_tag
助手构建一个 HTML 代码块。我现在面临的挑战是从一个数组中加入 HTML 个字符串,其中 HTML 个元素由 content_tag
.
RuboCop Rails/OutputSafety 参考。
例如:
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>
但是,如果我使用下面的 html_safe 方法,它将起作用。
%{<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>
问题是您将输出与来自 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 转义。
https://apidock.com/rails/ActionView/Helpers/OutputSafetyHelper/safe_join
在您的例子中,safe_join
方法根本没有对 out
数组中的字符串执行任何操作,因为它们已经是 html_safe。
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><li>Two</li>"
# 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 个条件:
safe_join
方法必须采用 html_safe 字符串数组。如果它们不是 html_safe,所有 html 标签都将被转义。- 不要将安全字符串与不安全字符串连接起来,否则不安全字符串将被转义。
如您所见,您没有满足第二个条件。
关于新方法的建议
.join("")
方法使结果字符串不安全,即使数组包含安全字符串也是如此。使用 safe_join
:
content_tag(:li, "One") +
content_tag(:li, "Two") +
safe_join(
options.collect do |option|
content_tag(:li, option)
end
)