150 votes

Meilleur moyen de créer un jeton unique dans les Rails?

Voici ce que j'utilise. Le jeton n'a pas nécessairement à être entendu à deviner, c'est plus comme une url courte identifiant qu'autre chose, et je veux le garder court. J'ai suivi quelques exemples que j'ai trouvés en ligne et dans le cas d'une collision, je pense que le code ci-dessous va recréer le jeton, mais je ne suis pas vraiment sûr. Je suis curieux de voir de meilleures suggestions, même si, comme cela se sent un peu rude sur les bords.

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

Ma colonne de base de données pour le jeton est un index unique et je suis également en utilisant validates_uniqueness_of :token sur le modèle, mais parce que ceux-ci sont créés dans des lots automatiquement, basée sur les actions d'un utilisateur dans l'application (ils passer une commande et d'acheter les jetons, essentiellement), il n'est pas possible d'avoir l'application renvoie une erreur.

Je pourrais aussi, je suppose, pour réduire le risque de collisions, ajouter une autre chaîne à la fin, quelque chose généré en fonction du temps ou quelque chose comme ça, mais je ne veux pas le jeton trop long.

325voto

Krule Points 4374

Juste pour référence future, création de coffre-fort aléatoire jeton de s'assurer de l'unicité du modèle (lors de l'utilisation de Ruby 1.9 et 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 a suggéré, et je suis d'accord, pour remplacer begin...end..while avec loop do...break unless...end dans cette réponse parce que la mise en œuvre antérieure peut obtenir supprimé dans le futur.

Edit 2:

Avec Rails 4 et préoccupations, je vous recommande de déplacement de ce de préoccupation.

# 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

50voto

Nate Bird Points 2237

Ryan Bates utilise un joli petit bout de code dans son Railscast sur la bêta invitations. Cela produit un de 40 caractères chaîne alphanumérique.

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

30voto

coreyward Points 26109

Il y a quelques jolies de la nappe de façons de le faire démontré dans cet article:

http://blog.logeek.fr/2009/7/2/creating-small-unique-tokens-in-ruby

Mon préféré de la liste est ceci:

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

17voto

Esse Points 887

Si vous voulez quelque chose qui sera unique vous pouvez utiliser quelque chose comme ceci:

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

cependant cela va générer de la chaîne de 32 caractères.

Il y a cependant autre manière:

require 'base64'

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

par exemple, pour les id que 10000, jeton généré serait comme "MTAwMDA=" (et vous pouvez facilement décoder pour id, il suffit de faire

Base64::decode64(string)

14voto

Vik Points 2959

Cela peut être utile :

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

Si vous souhaitez supprimer tous les caractères spéciaux que de le mettre en premier argument "+ / = " et n'importe quel caractère mis en second argument '0aZ' et 15 est la longueur ici .

Et si vous voulez supprimer les espaces et le caractère de nouvelle ligne de les ajouter des choses comme :

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

Espérons que cela permettra à tout le monde.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: