使用Symbol vs String作为params散列中的键的Rails

时间:2016-05-17 17:37:01

标签: ruby-on-rails ruby hash

如果我们使用字符串作为哈希键,Ruby需要评估字符串并查看其内容(并计算其上的哈希函数)并将结果与​​已存储的键的(哈希)值进行比较在哈希。

如果我们使用一个符号作为Hash键,它隐含它是不可变的,所以Ruby基本上只需要对象的id(哈希函数)与键的(哈希)对象-id进行比较。已存储在Hash中。 (快得多)。

但事情在Rails params中是HashWithIndifferentAccess的实例,如果我们写params[:some_key]它会将:some_key转换为'some_key'然后尝试寻找params hash的关键。 line 159

 def convert_key(key)
    key.kind_of?(Symbol) ? key.to_s : key
  end

因此,如果在Hash中将String作为键,查找速度很慢,为什么HashWithIndifferentAccess会将符号键转换为字符串。

2 个答案:

答案 0 :(得分:6)

原因是安全性。它在Ruby 2.2或更高版本中不再适用。

在Ruby 2.2符号没有被垃圾收集之前。这意味着,一旦通过文字(:my_symbol)或#to_sym创建了符号,它就会永远存在于

如果Rails使用符号而不是字符串,那么它将创建与请求中的params名称相对应的符号。攻击者可以使用名为param1param2,...的params发送请求,并通过使应用程序分配数十万个符号来耗尽服务器内存。

在Ruby 2.2或更高版本中不再是这种情况

答案 1 :(得分:0)

:symbol.to_s将始终创建新的实例字符串,而"string".to_sym将始终生成相同的符号。

p "string".to_sym.object_id
#=> 272028
p "string".to_sym.object_id
#=> 272028

p :symbol.to_sym.to_s.object_id
#=>70127441809260
p :symbol.to_sym.to_s.object_id
#=>70127441809160

因此,似乎该类的设计者将键存储为字符串,以避免在访问期间不必要地创建字符串,特别是如果使用hash.keys方法(它将键返回为字符串)。