Rails number_to_percentage和子怪异行为

时间:2018-01-10 12:16:21

标签: ruby-on-rails ruby regex

我正在尝试将大%数替换为缩短版本(10000% - > 10k%)。通常代码有效,但如果number_to_percentage使用它就会停止工作(使用 TOTALY SAME 字符串)。

Loading development environment (Rails 5.1.2)
2.3.1 :001 > "10000.000%".bytes
=> [49, 48, 48, 48, 48, 46, 48, 48, 48, 37]    
2.3.1 :002 > helper.number_to_percentage(10000).bytes
=> [49, 48, 48, 48, 48, 46, 48, 48, 48, 37] # totally same
2.3.1 :003 > helper.number_to_percentage(10000).sub(/(\d\d)\d\d\d(?:[.,]\d+)?\%$/){ "#{$1}k%" }
=> "k%"  # doesn't work
2.3.1 :004 > "10000.000%".sub(/(\d\d)\d\d\d(?:[.,]\d+)?\%$/){ "#{$1}k%" }
=> "10k%" # works

这会导致什么?有什么想法吗?

2 个答案:

答案 0 :(得分:3)

因为number_to_percentage返回ActiveSupport :: SafeBuffer而不是String。

helper.number_to_percentage(10000).class # => ActiveSupport::SafeBuffer

ActiveSupport :: SafeBuffer(它是String的子类)在诸如sub之类的不安全方法方面做了一些魔术。这就是为什么你会有一些惊喜。

答案 1 :(得分:2)

关键区别是:

"10000.000%".class #=> String
number_to_percentage(10000).class # => ActiveSupport::SafeBuffer

ActiveSupport::SafeBufferString的子类,包含UNSAFE_STRING_METHODS(包括subgsub)的概念。对于安全性而言,这个概念对于rails视图(通常使用number_to_percentage!)非常有用;防止XSS漏洞。

解决方法是将变量显式转换为String

number_to_percentage(10000).to_str.sub(/(\d\d)\d\d\d(?:[.,]\d+)?\%$/){ "#{$1}k%" }
=> "10k%"

(请注意,它是 to_str ,而不是to_sto_s只返回self,即ActiveSupport::SafeBuffer的实例;而to_str会返回常规String。)

This articlethis rails issue详细介绍了这个问题。

或者,您可以像这样编写代码,并按预期工作:

number_to_percentage(10000).sub(/(\d\d)\d\d\d(?:[.,]\d+)?%$/, '\1k%')
#=> "10k%"

我实际上更喜欢这种方法,因为你不再依赖于对(非线程安全)全局变量的修改。