Лучший способ создать уникальный токен в Rails?
вот что я использую. Токен не обязательно должен быть услышан, чтобы угадать, это больше похоже на короткий идентификатор url, чем что-либо еще, и я хочу, чтобы он был коротким. Я следил за некоторыми примерами, которые я нашел в интернете, и в случае столкновения,Я думаю приведенный ниже код воссоздаст токен, но я не совсем уверен. Мне любопытно увидеть лучшие предложения, хотя, как это чувствует себя немного грубо по краям.
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
на модели, но поскольку они создаются в пакетах автоматически на основе действий пользователя в приложении (они размещают заказ и покупают токены, по существу), невозможно, чтобы приложение выдавало ошибку.
я мог бы также, я думаю, чтобы уменьшить вероятность столкновений, добавить еще одну строку в конце, что-то сгенерированное на основе времени или что-то в этом роде, но я не хочу, чтобы маркер слишком долго.
10 ответов:
-- Update --
по состоянию на 9 января, 2015. решение теперь реализовано в рельсы 5реализация безопасного токена ActiveRecord.
-- рельсы 4 & 3 --
просто для дальнейшего использования, создания безопасного случайного токена и обеспечения его уникальности для модели (при использовании 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
Edit:
@kain предложил, и я согласился, чтобы заменить
begin...end..while
Сloop do...break unless...end
в этом ответе, потому что предыдущая реализация может быть удалена в будущем.Edit 2:
С рельсами 4 и проблемами я бы рекомендовал переместить это в беспокойство.
# 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
Райан Бейтс использует хороший немного кода в его Railscast на бета-приглашения. Это создает 40-символьную буквенно-цифровую строку.
Digest::SHA1.hexdigest([Time.now, rand].join)
есть несколько довольно гладких способов сделать это продемонстрировано в этой статье:
мой любимый список это:
rand(36**8).to_s(36) => "uur0cj2h"
это может быть поздний ответ, но во избежание использования цикла вы также можете вызвать метод рекурсивно. Он выглядит и чувствует себя немного чище для меня.
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 символов.
есть, однако, другой способ:
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 встроено. Используйте .
генерация GUID в RubyЭто было полезно для меня
вы можете пользователь 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"