Recently in a Phoenix project I needed to use a UUID column to represent an external identifier. I had previously used UUID’s with the
binary_id field type but it wasn’t immediately obvious how to use UUID’s for regular columns.
The migration is simple enough - just specify a
:uuid column type. In this case I set
null: false in the options to prevent null entries. I also have a unique_index on the
:external_id just in case. (UUID’s can be specified for test data, as later mentioned. It’s always best to have data integrity constraints at the database level.)
def change do create table(:teams) do add :external_id, :uuid, null: false add :name, :string, null: false timestamps() end create unique_index(:teams, [:external_id]) end
The schema definition is equally straight forward:
schema "teams" do field :external_id, Ecto.UUID, autogenerate: true field :name, :string timestamps() end
We set the field type to
Ecto.UUID and specify we want it automatically generated with the
autogenerate: true option. This is required if you want automatically generated UUID’s for each entry. Autogeneration happens before insertion if no value is already set. There is an important distinction between using the
:default options - the value given to
:default is calculated at compilation time, so all entries would have the same value per compile, whereas
:autogenerate is not.
Ecto handles the casting between a string representation of a UUID and database persistence (and vice versa). This is great because it means you can use specify UUID’s as strings in factories or test data, without the need to use a UUID generator.