Почему ActionView "select_tag" экранирует HTML в аргументе "options" при прямом вызове?
Итак, я просматривал очень скудную документацию, которая существует для ActionView, в частности, метод под названием select_tag
это просто существует, когда вызывается из файлов просмотра. Предположительно, это называется так:
select_tag name, option_tags, options
Документация ничего не говорит о name
очень мало о options
и описывает option_tags
только через примеры, которые рассматривают его как непрозрачное значение, которое должно быть получено из других функций.
Как всегда, единственный способ узнать что-либо о Rails - это перепроектировать его.
Поэтому я попытался запустить его непосредственно из консоли Rails, что сложно, поскольку Ruby не позволяет вам вызывать методы, определенные в модулях, если вы сначала не создадите класс и объект:
class H
include ActionView::Helpers::FormOptionsHelper
include ActionView::Helpers::FormTagHelper
end
H.new.options_for_select ["foo","bar"]
Вышеуказанное использование options_for_select
исходит из реального кода, который кто-то написал. Возвращаемое значение представляет собой строку:
"<option value=\"foo\">foo</option>\n<option value=\"bar\">bar</option>"
Очевидно, вы должны передать возвращаемое значение из option_for_select
(или одна из многих других связанных функций, которые создают сложности, о которых я не хочу говорить, например, генерирование тегов HTML из объектов ActiveRecord) в качестве option_tag
параметр select_tag
, За исключением случаев, когда вы копируете эту строку в буфер обмена и вставляете ее непосредственно в вызов функции, она не делает то, что вы ожидаете:
H.new.select_tag :my_name, "<option value=\"foo\">foo</option>\n<option value=\"bar\">bar</option>"
Возвращаемое значение:
"<select name=\"my_name\" id=\"my_name\"><option value="foo">foo</option>\n<option value="bar">bar</option></select>"
По крайней мере, это показывает, что name
параметр для.
Даже страннее, текст не экранируется, если вы передаете возвращаемое значение непосредственно select_tag
не позволяя печатать на консоли:
H.new.select_tag :name, H.new.options_for_select(["foo","bar"])
Возвращаемое значение:
"<select name=\"name\" id=\"name\"><option value=\"foo\">foo</option>\n<option value=\"bar\">bar</option></select>"
WTF здесь происходит?
1 ответ
В процессе написания этого вопроса я наткнулся на его ответ: Руби лгала мне (как всегда).
Когда вы оцениваете:
H.new.options_for_select ["foo","bar"]
Руби говорит вам, что результатом была строка. Но это только потому, что Прай и Ирб молча .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 рассматривает все строки как подозрительные, но можно пометить определенные строки как "безопасные", заключив их в ActiveSupport::SafeBuffer
,