Generando Guías en Ruby

142

Tengo un problema que realmente se resuelve fácilmente con Guids.

En particular, para un flujo de trabajo de restablecimiento de contraseña, me gustaría enviar un token Guid al correo electrónico de un usuario y hacer que restablezcan su contraseña utilizando el token. Como las guías son únicas, esto es bastante seguro y me ahorra el envío de contraseñas por correo electrónico, lo cual es riesgoso.

Noté que hay una gema Guid para Ruby; pero parece bastante viejo y escribe cosas en el sistema de archivos.

¿Alguien sabe de alguna otra gema que pueda crear un identificador único globalmente?

Sé que puedo recurrir a:

(0..16).to_a.map{|a| rand(16).to_s(16)}.join 

Pero en realidad no parece un GUID adecuado ...

Sam Azafrán
fuente
1
Usar una cadena aleatoria como esa no sería del todo correcto; ciertos bits en el UUID especifican variante y versión. Para un UUID aleatorio, probablemente desee la variante 2 (RFC 4122) y la versión 4, en cuyo caso 6 ciertos bits deben establecerse en los valores correctos.
jtpereyda
1
Sí, @dafrazzman tiene razón. La unión aleatoria de algo que "se asemeja a un UUID" no garantiza la unicidad. Si bien ningún UUID está realmente garantizado, construir uno con números aleatorios es MUCHO más susceptible a colisiones y no podría ser digno de la etiqueta "UUID". Definitivamente ve con SecureRandom.uuid!
dooleyo

Respuestas:

312

A partir de Ruby 1.9, la generación de uuid está integrada. Usa la SecureRandom.uuidfunción.

Por ejemplo:

require 'securerandom'
SecureRandom.uuid # => "96b0a57c-d9ae-453f-b56f-3b154eb10cda"
J _
fuente
55
SecureRandom.uuid genera un UUID aleatorio, por lo que no se garantiza que sea único. Si solo desea una cadena aleatoria que probablemente sea única, estará bien usarla. Sin embargo, si desea algo que garantice que sea único, necesitará usar algo que incluya la dirección MAC, la marca de tiempo, etc.
Mike Dotterer
23
Para ahorrarle un poco de búsqueda, necesitará requerir 'securerandom'
Jesse Shieh
8
No se garantiza que sea único, pero para la mayoría de los propósitos prácticos, es seguro asumir que es único. Ver: stackoverflow.com/questions/2977593/…
Jesse Shieh
si SecureRandom.uuid sigue RFC 4122 como dice según la documentación, ¿eso no significa que tiene un campo de marca de tiempo? Salvo la concurrencia, ¿no significa eso único?
Michael K Madison el
@MichaelKMadison AFAIK Ruby usa la variante "v4" de RFC 4122, que no usa una marca de tiempo, por lo que la posibilidad de colisión no es nula, pero en la práctica también podría serlo
Edd Morgan
38

Cómo crear tokens pequeños y únicos en Ruby

>> require 'digest'
=> []
>> Digest::SHA1.hexdigest("some-random-string")[8..16]
=> "2ebe5597f"

>> SecureRandom.base64(8).gsub("/","_").gsub(/=+$/,"")
=> "AEWQyovNFo0" 

>> rand(36**8).to_s(36)
=> "uur0cj2h"
Simone Carletti
fuente
35

Usamos UUIDTools y no tenemos problemas con él.

Avdi
fuente
2
'uuidtools' funciona, incluso cuando el sistema no tiene una dirección MAC. 'uuid' falla en este caso.
grefab
3
A diferencia de la gema uuid, uuidtools no guarda ningún archivo de estado. Los problemas de permisos con el archivo de estado hacen que la gema uuid sea algo incómoda de usar con múltiples usuarios.
Wayne Conrad
1
Parece que las herramientas UUID ya no se mantienen. No ha habido ningún compromiso con el repositorio github en más de 2 años
Sudhanshu Mishra
22

¿ Viste UUIDTools ?

UUIDTools fue diseñado para ser una biblioteca simple para generar cualquiera de los diversos tipos de UUID (o GUID si prefiere llamarlos así). Cumple con RFC 4122 siempre que sea posible.

Andrew Hare
fuente
16

Google produce la siguiente biblioteca de Ruby:

http://raa.ruby-lang.org/project/ruby-guid/

Además, en http://www.ruby-forum.com/topic/99262 dicen que puede instalar una gema (ejecutar gem uuiden la línea de comando para instalarla) y luego hacer

gem 'uuid'
puts UUID.new

en su código para ver un nuevo UUID.

(Sugerencia: busqué en Google para guid ruby )

Marc W
fuente
Gracias, lo vi pero es súper viejo, ¿solo busco algo activo, como una gema reciente?
Lance Pollard, el
¿Qué tal la gema uuid que agregué a mi respuesta? ¿O es a eso a lo que te referías?
Marc W
55
Eso es extraño ... también busqué en Google "guid ruby", y todo lo que obtuve fue esta publicación SO :-P
Jason Whitehorn
3

Para crear un GUID apropiado, mysql, varchar 32

SecureRandom.uuid.gsub('-','').upcase
Aaron Henderson
fuente
OSecureRandom.hex.upcase
Daniel Antonio Nuñez Carhuayo
3

Pequeña actualización de la respuesta de Simone Carletti:

SecureRandom.base64 (8) .gsub ("/", "_"). Gsub (/ = + $ /, "")

=> "AEWQyovNFo0"

se puede reemplazar con:

SecureRandom.urlsafe_base64 (8)

Алексей Лещук
fuente
1

Mientras programaba a altas horas de la noche, se me ocurrió la siguiente solución (basada en Simone) para generar un GUID único en Rails. No estoy orgulloso de ello, pero funciona bastante bien.

while Order.find_by_guid(guid = rand(36**8).to_s(36).upcase).present?; end
robotmay
fuente
2
Espero que te hayas acordado de indexar tu columna guid esa noche
nurettin
0

Cuando utilicé gemas uuid recomendadas en esta pregunta, nadie puede generar un UUID único y aleatorio. Mi respuesta es una solución: si tenemos gema más tarde para satisfacer la solicitud, será mejor que uses gema en Ruby.

Intento las gemas de líquido más recomendadas en esta pregunta, pero nadie me satisface, necesitamos un líquido único y aleatorio. Ejecuto directamente el comando del sistema uuidgenen ruby, y me gusta el resultado, y comparto aquí.

puts `uuidgen`
8adea17d-b918-43e0-b82f-f81b3029f688
puts `uuidgen`
6a4adcce-8f64-41eb-bd7e-e65ee6d11231
puts `uuidgen`
51d5348b-8fc3-4c44-a6f7-9a8588d7f08a
puts `uuidgen`
332a0fa3-7b07-41e1-9fc8-ef804a377e4e

Si se compara con la uuidgema, sabrá la diferencia.

irb(main):003:0> uuid.generate
=> "40cdf890-ebf5-0132-2250-20c9d088be77"
irb(main):004:0> uuid.generate
=> "4161ac40-ebf5-0132-2250-20c9d088be77"

El entorno de prueba es el entorno de Linux y Mac OS.

BMW
fuente
2
una puts `...`está haciendo básicamente una llamada al sistema para uuidgen(3)que falle en cualquier otra plataforma que no sea Linux, añade cantidades extremas de tiempo de ejecución, y en general es una práctica muy contrario a la intuición de codificación. ¿Por qué elegirías tal método?
Dwight Spencer
1
@DwightSpencer Creo que estamos en un área diferente con un propósito diferente. Lo que le importa no está en mis preocupaciones, como el tiempo de ejecución, la amplia gama de sistemas operativos, las migraciones de código. Me importa que el código pueda funcionar en Mac OS o Linux y obtener el resultado correcto que necesito. Por supuesto, si puedes encontrar un camino en Ruby y obtener el mismo resultado que el comando uuidgen, estoy feliz de usarlo. Pero hasta ahora, no encontré ninguno.
BMW
1
Tanto @J_ como @ simone-carletti ya han señalado una mejor manera en esta publicación. Por mi parte, sugeriría SecureRandomque está realizando la misma función en el mismo método, uuidgenpero a diferencia uuidgendel uso del bloqueo / dev / random solo SecureRandomusa la biblioteca de openssl primero, luego cae a dev / urandom y finalmente / dev / random en los intentos de hacer generación de aleatorización sin bloqueo.
Dwight Spencer
0

Esta es una técnica neet que aprendí de JavaScript:

def uuid
    "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx".gsub("x") do
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[rand(36)]
    end
end

Aunque de una manera más 'rubí' también se podría hacer:

def uuid
    "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx".gsub("x") do
        rand(16).to_s(16)
    end
end
Sancarn
fuente