为什么在直接调用时 ActionView 的 "select_tag" 转义其 "options" 参数中的 HTML?

Why does ActionView's "select_tag" escape the HTML in its "options" argument when called directly?

所以我一直在浏览 ActionView 的非常糟糕的文档,特别是一个名为 select_tag 的方法,它只在从视图文件调用时存在。据说,它是这样称呼的:

select_tag name, option_tags, options

documentationname 只字未提,对 options 也很少提及,仅通过将其视为不透明的示例来描述 option_tags必须从其他函数获取的值。

一如既往,了解 Rails 的唯一方法是对其进行逆向工程。

所以我直接从 Rails 控制台尝试 运行 它,这很棘手,因为 Ruby 不允许您调用模块中定义的方法,除非您创建 class 和第一个对象:

class H
  include ActionView::Helpers::FormOptionsHelper
  include ActionView::Helpers::FormTagHelper
end

H.new.options_for_select ["foo","bar"]

上面options_for_select的用法来自别人写的实际代码。 return 值是一个字符串:

"<option value=\"foo\">foo</option>\n<option value=\"bar\">bar</option>"

显然,您应该从 option_for_select 传递 return 值(或者许多其他相关函数之一,这些函数引入了我不想谈论的并发症,例如生成HTML 来自 ActiveRecord 对象的标签)作为 select_tagoption_tag 参数。除非您将该字符串复制到剪贴板并将其直接粘贴到函数调用中,否则它不会执行您期望的操作:

H.new.select_tag :my_name, "<option value=\"foo\">foo</option>\n<option value=\"bar\">bar</option>"

Return 值:

"<select name=\"my_name\" id=\"my_name\">&lt;option value=&quot;foo&quot;&gt;foo&lt;/option&gt;\n&lt;option value=&quot;bar&quot;&gt;bar&lt;/option&gt;</select>"

至少这揭示了 name 参数的用途。

更奇怪的是,如果您将 return 值 直接 传递给 select_tag 而不让它在控制台上打印,则文本不会被转义:

H.new.select_tag :name, H.new.options_for_select(["foo","bar"])

Return 值:

"<select name=\"name\" id=\"name\"><option value=\"foo\">foo</option>\n<option value=\"bar\">bar</option></select>"

这是怎么回事?

在写这个问题的过程中,我偶然发现了它的答案:Ruby 一直在骗我(就像它一直那样)。

当您评价时:

H.new.options_for_select ["foo","bar"]

Ruby 告诉您结果是一个字符串。但这只是因为 Pry 和 Irb 都在所有事情上默默地调用 .to_s,而从 options_for_select 返回的东西有一个 to_s。真相:

(H.new.options_for_select ["foo","bar"]).class
=> ActiveSupport::SafeBuffer
ActiveSupport::SafeBuffer.new("<foo>")
=> "<foo>"

因此,无论是谁编写这些方法,都假设您想将用户提供的原始字符串合并到您的 <select> 标记中,并且这些字符串可能包含 HTML/JavaScript 注入尝试,因此必须对它们进行转义.

ActiveView 将所有字符串视为可疑字符串,但可以将某些字符串标记为 "safe",方法是将它们包装在 ActiveSupport::SafeBuffer.