Using UUIDs with Crystal Amber

Posted on Sep 9, 2018

Crystal Amber

In some situations it's ideal to be able to hide the ID number in a database table. Here's how to do it using Crystal Amber and the Granite ORM.

Create your model

1
amber g model WebLink url:string

Edit the migration file to use either a VARCHAR or UUID if it supports it (Hint: Postgres does!). To use a hex string instead, stick with VARCHAR.

1
2
3
4
5
6
7
8
9
10
11
-- +micrate Up
CREATE TABLE web_links (
  id UUID PRIMARY KEY,
  url VARCHAR,
  created_at TIMESTAMP,
  updated_at TIMESTAMP
);


-- +micrate Down
DROP TABLE IF EXISTS web_links;

Edit the model file to include the UUID library, set the Primary Key as a string and turn off auto increment. Then add the before_create macro to assign a new UUID on creation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require "uuid"
class WebLink < Granite::Base
  adapter pg
  table_name web_links

  # id : Int64 primary key is created for you
  primary id : String, auto: false
  field url : String
  timestamps
  before_create :assign_id

  def assign_id
	@id = UUID.random.to_s
  end
end

Alternatively, use UUID.random.hexstring.to_s for an alternate style (e.g. 2d10e1a2fa89425197d62f94c6cf07dc). The UUID database data type will convert this automatically so make sure to set the data type to VARCHAR.

To use shorter IDs chop the hexstring down by using the range syntax [0..6], replacing 6 with the desired length, and then check for duplicates before creating the table row.

1
2
3
4
5
6
7
def assign_id
  potential_id = UUID.random.hexstring.to_s[0..6]
	while WebLink.find(potential_id)
	  potential_id = UUID.random.hexstring.to_s[0..6]
	end
  @id = potential_id
end

That's it! Make sure to run crystal db migrate before running the application.

Like this article? Sign up to updates - no spam!