在ActionView :: OutputBuffer上调用时为什么URI.escape失败?

时间:2012-02-27 18:00:37

标签: ruby-on-rails ruby-on-rails-3

我正在将应用程序从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'

此外,在OutputBuffer上调用to_s返回相同的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,这可以有效地解决问题......但是我的问题'为什么会发生这种情况'仍然存在,例如这是一个错误,我应该报告,还是我做错了什么?

3 个答案:

答案 0 :(得分:19)

这是bug in Rails

  

当在ActiveSupport :: SafeBuffer上使用块调用gsub时,在调用块时,用于引用子匹配的全局变量$ 1,$ 2等并不总是正确设置(不再是?)。

这就是为什么URI.escape(以及使用gsub()的任何其他函数都会在ActiveSupprt :: Safebuffer上失败。

关于这一点有several discussions,显然现在最安全的路线是在将SafeBuffer传递给可以调用gsub的任何东西之前调用to_str,例如URI.encodeescape_javascript和类似的功能。

关于to_s返回同一个类的另一个问题 - 显然安全的缓冲区将返回自身,而不是一个裸字符串,这是设计的。为了获得真正的字符串,可以使用.to_str

答案 1 :(得分:1)

这是因为Rails 3引入了safe buffers

的概念

在Rails3中,默认情况下,您的视图受XSS保护,除非您明确使用raw()帮助器或html_safe

,否则将安全地转义所有呈现

答案 2 :(得分:0)

这是我目前在Rails 5中遇到的一个愚蠢的错误。我的愚蠢解决方法是做类似的事情

ob = ActionView::OutputBuffer.new("test test")
URI.escape(ob.to_sym.to_s)

同样有效,但我仍在寻找更清洁的解决方案。