Generating Guids in Ruby

Generating GUIDs in Ruby

As of Ruby 1.9, uuid generation is built-in. Use the SecureRandom.uuid function.

For example:

require 'securerandom'
SecureRandom.uuid # => "96b0a57c-d9ae-453f-b56f-3b154eb10cda"

I need to generate uuid for my rails application. What are the options(gems) I have?

There are plenty of options, I recommend not to add additional dependencies and use SecureRandom which is builtin:

SecureRandom.uuid #=> "1ca71cd6-08c4-4855-9381-2f41aeffe59c"

See other possible formats here.

Ruby On Rails: Initialize object with random GUID on .new?

you can use the after_initialize callback, that is called every time an object of your class is instantiated.

 class User < ActiveRecord::Base
after_initialize :generate_guid, unless: :guid
def generate_guid
self.guid = # your method here
end
end

you can also set this field to be a primary key in your migration:

create_table :users, primary_key: :guid do |t| 

however, do you really need to create a guid every time you instantiate an object ? It seems really computationaly expensive. And as someone commented, be warned that rails sometimes behaves weirdly when you get out of common patterns and conventions...

How can I convert a GUID into a byte array in Ruby?

Your example GUID is in a Microsoft specific format. From Wikipedia:

Other systems, notably Microsoft's marshalling of UUIDs in their COM/OLE libraries, use a mixed-endian format, whereby the first three components of the UUID are little-endian, and the last two are big-endian.

So in order to get that result, we have to move the bits around a little. Specifically, we have to change the endianess of the first three components. Let's start by breaking the GUID string apart:

guid = '35918bc9-196d-40ea-9779-889d79b753f0'
parts = guid.split('-')
#=> ["35918bc9", "196d", "40ea", "9779", "889d79b753f0"]

We can convert these hex-strings to binary via:

mixed_endian = parts.pack('H* H* H* H* H*')
#=> "5\x91\x8B\xC9\x19m@\xEA\x97y\x88\x9Dy\xB7S\xF0"

Next let's swap the first three parts:

big_endian = mixed_endian.unpack('L< S< S< A*').pack('L> S> S> A*')
#=> "\xC9\x8B\x915m\x19\xEA@\x97y\x88\x9Dy\xB7S\xF0"
  • L denotes a 32-bit unsigned integer (1st component)
  • S denotes a 16-bit unsigned integer (2nd and 3rd component)
  • < and > denote little-endian and big-endian, respectively
  • A* treats the remaining bytes as an arbitrary binary string (we don't have to convert these)

If you prefer an array of bytes instead of a binary string, you'd just use:

big_endian.bytes
#=> [201, 139, 145, 53, 109, 25, 234, 64, 151, 121, 136, 157, 121, 183, 83, 240]

PS: if your actual GUID isn't Microsoft specific, you can skip the swapping part.

Generating a short UUID string using uuidtools In Rails

You don't need uuidtools for this. You can use Secure Random for this.

[1] pry(main)> require "securerandom"
=> true
[2] pry(main)> SecureRandom.hex(20)
=> "82db4d707c4c5db3ebfc349da09c991b7ca0faa1"
[3] pry(main)> SecureRandom.base64(20)
=> "CECjUqNvPBaq0o4OuPy8RvsEoCY="

Passing 4 and 5 to hex will generate 8 and 10 character hex strings respectively.

[5] pry(main)> SecureRandom.hex(4)
=> "a937ec91"
[6] pry(main)> SecureRandom.hex(5)
=> "98605bb20a"

How to create ruby uuid from bytes?

Another way to skin a cat, simple and easy to understand:

a = [107, 97, 155, 242, 36, 52, 182, 87, 67, 223, 163, 166, 7, 175, 123, 223]

def _guid(ints, reverse=false)
hexes = ints.map { |b| b.to_s(16).rjust(2, '0') }
return hexes.reverse.join if reverse
hexes.join
end

def guid(ints)
'%s-%s-%s-%s-%s' % [
_guid(ints[0...4], true),
_guid(ints[4...6], true),
_guid(ints[6...8], true),
_guid(ints[8...10]),
_guid(ints[10..-1]),
]
end

puts guid a # => f29b616b-3424-57b6-43df-a3a607af7bdf

How to retrieve a GUID and value from a string in ruby

Here's an approach that will work - split up the target string into tokens by whitespace and equals-sign characters (tokens=str.split(/[= ]/)) and create a Hash out of them (Hash[*tokens]). The result is a Hash whose keys are the token before the equals sign and the values are the ones after it:

s = 'word=0 id=891efc9a-2210-4beb-a19a-5e86b2f8a49f'
h = Hash[*s.split(/[= ]/)]
h # => {"word"=>"0", "id"=>"891efc9a-2210-4beb-a19a-5e86b2f8a49f"}
h['word'] # => "0"
h['id'] # => "891efc9a-2210-4beb-a19a-5e86b2f8a49f"

Of course, it will break if your "keys" or "values" contain equal signs or spaces but it works for your example.



Related Topics



Leave a reply



Submit