How to use UUIDs as Primary Key with ecto
Recently, I was playing around with Phoenix Framework (version: 0.13.1) with Postgres as the database. Instead of using IDs for primary key, I wanted to use UUIDs. Since Phoenix and associated projects haven’t hit 1.0 yet, api is still under flux.
As of this post, there are two resources with instructions on how to achieve this and both didn’t seem to work. A stackoverflow post and a google group discussion.
Since ecto version 0.12.1 using UUIDs as primary key coudn’t be any easier. Here is how to do it:
The migration that creates the table will need to be aware of the fact that ID column is going to be of UUID type.
defmodule Blog.Repo.Migrations.CreatePost do
use Ecto.Migration
def up do
# Here we are specifying
# to not use default auto-incrementing id as primary key
create table(:posts, primary_key: false) do
# Here we explicitly set the type of
# id column as uuid and assign it as primary key
add :id, :uuid, primary_key: true
add :title, :string
add :body, :text
timestamps
end
end
def down do
drop table(:posts)
end
end
We will also need to update our model definition so that it can auto-generate UUIDs for primary keys.
defmodule Blog.Post do
use Blog.Web, :model
# :binary_id is managed by drivers/adapters,
# it will be UUID for mysql, postgres
# but can be ObjectID if later you decide to use mongo
@primary_key {:id, :binary_id, autogenerate: true}
schema "posts" do
field :title, :string
field :body, :string
timestamps
end
@required_fields ~w(title body)
@optional_fields ~w()
@doc """
Creates a changeset based on the `model` and `params`.
If `params` are nil, an invalid changeset is returned
with no validation performed.
"""
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
end
end
And that is all you need to use UUIDs from primary keys with ecto and phoenix framework.
As an aside, I really like how these projects are shaping up. Also, the community around Elixir and Phoenix is absolutely fantastic. It took me no more than 5 minutes to figure this out by hopping on Elixir IRC and José Valim himself explaining how to solve this problem.