Ruby on rails 在Ruby/Rails中压缩十六进制字符串

Ruby on rails 在Ruby/Rails中压缩十六进制字符串,ruby-on-rails,ruby,mongodb,Ruby On Rails,Ruby,Mongodb,我正在使用MongoDB作为我正在构建的Rails应用程序的后端。默认情况下,Mongo会为其记录生成24个字符的十六进制ID,以简化分片,因此我的URL最终看起来像: example.com/companies/4b3fc1400de0690bf2000001/employees/4b3ea6e30de0691552000001 这不是很漂亮。我希望坚持Rails url约定,但也保留数据库中的这些ID。我认为一个很好的折衷方案是使用更多字符将这些十六进制ID压缩为较短的集合,这样它们看起来

我正在使用MongoDB作为我正在构建的Rails应用程序的后端。默认情况下,Mongo会为其记录生成24个字符的十六进制ID,以简化分片,因此我的URL最终看起来像:

example.com/companies/4b3fc1400de0690bf2000001/employees/4b3ea6e30de0691552000001
这不是很漂亮。我希望坚持Rails url约定,但也保留数据库中的这些ID。我认为一个很好的折衷方案是使用更多字符将这些十六进制ID压缩为较短的集合,这样它们看起来就像:

example.com/companies/3ewqkvr5nj/employees/9srbsjlb2r
然后在我的控制器中,我将反转压缩,获得原始的十六进制id并使用它来查找记录

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


谢谢

您可以使用base64使其更短。请确保您使用的是“-”和“\”而不是“+”和“/”。您还可以切碎填充=

将十六进制值转换为基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

可以用高于
16
的基数表示十六进制id,以缩短其字符串表示形式。Ruby内置了对从
2
36
的基本操作的支持

b36 = '4b3fc1400de0690bf2000001'.hex.to_s(36)
# => "29a6dblglcujcoeboqp"
要将其转换回24个字符的字符串,可以执行以下操作:

'%024x' % b36.to_i(36)
# => "4b3fc1400de0690bf2000001"
为了实现更好的“压缩”,可以在高于
36
的基础上表示id。有一些Ruby库可以帮助您实现这一点。gem就是这样一个库


我建议使用base
62
表示法,因为它只使用
0-9
a-z
a-z
字符,这意味着默认情况下它是URL安全的。

即使使用base 62表示法,最终也会得到16个字符的ID:

'4b3fc1400de0690bf2000001'.hex.to_base_62  
# => "UHpdfMzq7jKLcvyr"
稍微避开Rails惯例,另一个折衷方案是使用对象在日期创建的
的基32表示作为“URL id”

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

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

我该怎么做?我曾尝试在字符串ID上使用Base64.encode64,但这只会使它们变长。此代码段说明了如何使用Base64.encode64使ID变长,因为您将它们用作字符串而不是二进制数据。