在Rails中创build唯一标记的最佳方法是什么?

这是我正在使用的。 令牌不一定要被听到猜测,它更像是一个简短的URL标识符比其他任何东西,我想保持简短。 我跟着我在网上find的一些例子,如果发生碰撞, 我认为下面的代码会重新创build令牌,但是我不确定。 我很好奇,看到更好的build议,但是,这感觉有点粗糙的边缘。

def self.create_token random_number = SecureRandom.hex(3) "1X#{random_number}" while Tracker.find_by_token("1X#{random_number}") != nil random_number = SecureRandom.hex(3) "1X#{random_number}" end "1X#{random_number}" end 

我的令牌数据库列是一个唯一的索引,我也在模型上使用了validates_uniqueness_of :token ,但是因为这些是根据用户在应用程序中的操作自动创build的(他们下了订单并购买了令牌,本质上),应用程序抛出一个错误是不可行的。

我想我也可以减less碰撞的机会,在最后附加另一个string,根据时间或类似的东西生成一些东西,但是我不希望令牌太长。

– 更新 –

截至2015年1月9日,解决scheme现在在Rails 5 ActiveRecord的安全令牌实现中实现 。

– Rails 4&3 –

只是为了将来的参考,创build安全的随机标记,并确保它的唯一性(当使用Ruby 1.9和ActiveRecord):

 class ModelName < ActiveRecord::Base before_create :generate_token protected def generate_token self.token = loop do random_token = SecureRandom.urlsafe_base64(nil, false) break random_token unless ModelName.exists?(token: random_token) end end end 

编辑:

@ kainbuild议,我同意,以取代begin...end..while loop do...break unless...end在这个答案,因为以前的实施可能会被删除在将来。

编辑2:

随着Rails 4和关注,我会build议移动这个问题。

 # app/models/model_name.rb class ModelName < ActiveRecord::Base include Tokenable end # app/models/concerns/tokenable.rb module Tokenable extend ActiveSupport::Concern included do before_create :generate_token end protected def generate_token self.token = loop do random_token = SecureRandom.urlsafe_base64(nil, false) break random_token unless self.class.exists?(token: random_token) end end end 

Ryan Bates在他的Railscast上使用了一小段代码来testingbeta版本 。 这会产生一个40个字符的字母数字string。

 Digest::SHA1.hexdigest([Time.now, rand].join) 

在这篇文章中演示了一些非常漂亮的方法:

https://web.archive.org/web/20121026000606/http://blog.logeek.fr/2009/7/2/creating-small-unique-tokens-in-ruby

我最喜欢的列表是这样的:

 rand(36**8).to_s(36) => "uur0cj2h" 

这可能是一个迟到的反应,但为了避免使用循环,你也可以recursion地调用这个方法。 它看起来和感觉稍微清洁一点。

 class ModelName < ActiveRecord::Base before_create :generate_token protected def generate_token self.token = SecureRandom.urlsafe_base64 generate_token if ModelName.exists?(token: self.token) end end 

如果你想要一些独特的东西,你可以使用这样的东西:

 string = (Digest::MD5.hexdigest "#{ActiveSupport::SecureRandom.hex(10)}-#{DateTime.now.to_s}") 

然而这会产生32个字符的string。

有另外的方法:

 require 'base64' def after_create update_attributes!(:token => Base64::encode64(id.to_s)) end 

例如id为10000,生成的令牌就像“MTAwMDA =”(你可以很容易地解码为id,只是使

 Base64::decode64(string) 

这可能会有所帮助:

 SecureRandom.base64(15).tr('+/=', '0aZ') 

如果你想删除任何特殊字符而不是第一个参数'+ / ='和任何字符放在第二个参数'0AZ'和15是在这里的长度。

如果你想删除多余的空格和新行字符,比添加如下的东西:

 SecureRandom.base64(15).tr('+/=', '0aZ').strip.delete("\n") 

希望这对任何人都有帮助。

试试这个方法:

从Ruby 1.9开始,uuid代是内置的。 使用SecureRandom.uuid函数。
在Ruby中生成Guid

这对我有帮助

你可以用户has_secure_token https://github.com/robertomiranda/has_secure_token

使用起来非常简单

 class User has_secure_token :token1, :token2 end user = User.create user.token1 => "44539a6a59835a4ee9d7b112b48cd76e" user.token2 => "226dd46af6be78953bde1641622497a8" 

创build一个合适的,mysql,varchar 32 GUID

 SecureRandom.uuid.gsub('-','').upcase 
 def generate_token self.token = Digest::SHA1.hexdigest("--#{ BCrypt::Engine.generate_salt }--") end