Почему URI.escape не работает при вызове ActionView:: OutputBuffer?

Я обновляю приложение от Rails 2 до Rails 3. По-видимому, вызов render() теперь возвращает ActionView::OutputBuffer, а не String. Мне нужно передать результаты render() на URI.escape(), и это происходит с ошибкой...

Вот мое краткое тестирование в консоли

ob = ActionView::OutputBuffer.new("test test")
URI.escape(ob)
    `NoMethodError: undefined method 'each_byte' for nil:NilClass`. 
        from /opt/ruby19/lib/ruby/1.9.1/uri/common.rb:307:in `block in escape'
        from ..../ruby/1.9.1/gems/activesupport-3.2.1/lib/active_support/core_ext/string/output_safety.rb:160:in `gsub'
        from ..../ruby/1.9.1/gems/activesupport-3.2.1/lib/active_support/core_ext/string/output_safety.rb:160:in `gsub'
        from /opt/ruby19/lib/ruby/1.9.1/uri/common.rb:304:in `escape'
        from /opt/ruby19/lib/ruby/1.9.1/uri/common.rb:623:in `escape'

Кроме того, вызов to_s на OutputBuffer возвращает тот же класс OutputBuffer, поэтому я не могу даже преобразовать этот буфер в честную строку?

ob.to_s.class 
    ActionView::OutputBuffer

Конечно, вызов URI.escape( "test test" ) возвращает "test %20test", как и ожидалось, поэтому это не проблема с URI.

Среда:

  • ruby ​​1.9.3p125 (2012-02-16 версия 34643) [i686-linux]
  • Rails 3.2.1

Мой вопрос: Почему это происходит и как я могу обойти эту проблему?

Обновление:. По-видимому, использование '' + ob как формы ob.to_s преобразует OutputBuffer в String, что эффективно работает вокруг проблемы... Но мой вопрос "почему это происходит" все еще остается, например это ошибка, я должен сообщить об этом, или я делаю что-то неправильно?

Ответы

Ответ 1

Это ошибка в Rails:

При вызове gsub с блоком в ActiveSupport:: SafeBuffer глобальные переменные $1, $2 и т.д. для ссылок на подматрицы не всегда правильно установлены (больше?) при вызове блока.

Вот почему URI.escape(и любая другая функция, использующая gsub(), не будет работать в ActiveSupprt:: Safebuffer.

Есть несколько обсуждения об этом, по-видимому, теперь самый безопасный маршрут - это позвонить в_процесс перед тем, как передать SafeBuffer во все, что может вызвать gsub, например URI.encode, escape_javascript и аналогичные функции.

Мой другой вопрос о to_s возвращении того же класса - очевидно, безопасный буфер вернется сам, а не голый String, это по дизайну. Чтобы получить истинную строку, можно использовать .to_str.

Ответ 2

Это связано с тем, что Rails 3 представила концепцию безопасных буферов

В Rails3 ваши представления защищены XSS по умолчанию, делая все рендеринг безопасным с экранированием, если вы явно не используете помощника raw() или html_safe