压缩Ruby / Rails中的十六进制字符串

时间:2010-01-02 22:45:40

标签: ruby-on-rails ruby mongodb

我正在使用MongoDB作为我正在构建的Rails应用程序的后端。默认情况下,Mongo会为其记录生成24个字符的十六进制ID,以便更轻松地进行分片,因此我的网址看起来像:

example.com/companies/4b3fc1400de0690bf2000001/employees/4b3ea6e30de0691552000001

哪个不太漂亮。我想坚持使用Rails url约定,但也要将这些ID保留在数据库中。我认为一个愉快的妥协是使用更多字符将这些hex id压缩为更短的集合,所以它们看起来像:

example.com/companies/3ewqkvr5nj/employees/9srbsjlb2r

然后在我的控制器中,我将反转压缩,获取原始的十六进制ID并使用它来查找记录。

我的问题是,来回转换这些ID的最佳方法是什么?我当然希望它们尽可能短,但也是安全且易于转换的。

谢谢!

3 个答案:

答案 0 :(得分:5)

您可以在高于16的基数中表示十六进制ID,以使其字符串表示更短。 Ruby内置支持使用从236的基础。

b36 = '4b3fc1400de0690bf2000001'.hex.to_s(36)
# => "29a6dblglcujcoeboqp"

要将其转换回24个字符的字符串,您可以执行以下操作:

'%024x' % b36.to_i(36)
# => "4b3fc1400de0690bf2000001"

要实现更好的“压缩”,您可以将基数中的ID表示为高于36。有一些Ruby库可以帮助你。 all-your-base gem就是这样一个库。

我推荐基本62代表,因为它只使用0-9a-zA-Z字符,这意味着默认情况下它是网址安全的。

答案 1 :(得分:1)

即使使用基础62表示,您最终仍会使用仍然难以处理的16个字符ID:

'4b3fc1400de0690bf2000001'.hex.to_base_62  
# => "UHpdfMzq7jKLcvyr"

Sidestepping Rails约定,另一个折衷方案是使用“URL id”作为对象created_at日期的基本32表示。

aCompany.created_at
# => Sat Aug 13 20:05:35 -0500 2011
aCompany.created_at.to_i.to_s(32)
# => "174e7qv"

通过这种方式,您可以获得超短ID(7个字符),而无需跟踪特殊用途属性(在MongoMapper中,只需在模型中添加timestamps!即可获得自动created_atupdated_at属性)。

答案 2 :(得分:0)

您可以使用base64缩短版本。确保使用' - '和'_'代替'+'和'/'。你也可以砍掉padding =。

将十六进制值转换为base 64的代码

def MD5hex2base64(str)
  h1=[].clear

  # split the 32 byte hex into a 16 byte array
  16.times{ h1.push(str.slice!(0,2).hex) }
  # pack (C* = unsigned char), (m = base64 encoded output)
  [h1.pack("C*")].pack("m")
end