Reputation: 17701
I have a schema like this:
defmodule Ticketing.User do
use Ticketing.Web, :model
schema "users" do
field :first_name, :string
field :last_name, :string
field :email, :string
field :hashed_password, :string
field :password, :string, virtual: true
field :active, :boolean, default: false
field :activation_key, :string, default: Ecto.UUID.generate
field :description, :string
timestamps()
end
@doc """
Builds a changeset based on the `struct` and `params`.
"""
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:first_name, :last_name, :email, :hashed_password, :password,
:active])
|> validate_required([:first_name, :last_name, :email, :password])
end
end
All new users have same UUID. does default value in schema evaluate only once? Should I implement the default value in changeset instead of schema?
Upvotes: 1
Views: 1588
Reputation: 19
You could change the type to Ecto.UUID
, and set the :autogenerate
option to true. Not 100% sure if this will work, but worth a shot :)
Upvotes: -1
Reputation: 222198
Like @Mick MacCallum said, :default
is evaluated at compile time in your code. If you're using PostgreSQL, you can fix this by changing the column's default value in the database to be gen_random_uuid()
. This will make PostgreSQL itself generate a random UUID value for each record. gen_random_uuid()
requires the pgcrypto
PostgreSQL extension.
Generate a new migration:
$ mix ecto.gen.migration add_default_to_users_activation_key
and replace the newly created file's contents with:
defmodule MyApp.Repo.Migrations.AddDefaultToUsersActivationKey do
use Ecto.Migration
def up do
execute "CREATE EXTENSION IF NOT EXISTS \"pgcrypto\";"
alter table(:users) do
modify :activation_key, :uuid, default: fragment("gen_random_uuid()")
end
end
def down do
alter table(:users) do
modify :activation_key, :uuid
end
end
end
You should also add read_after_writes: true
to the field
declaration of activation_key
in web/models/user.ex
so that activation_key
is read back from the database after inserts:
schema "users" do
field :activation_key, Ecto.UUID, read_after_writes: true
end
Demo:
iex(1)> %MyApp.User{name: "John Doe"} |> MyApp.Repo.insert!
[debug] QUERY OK db=9.6ms
INSERT INTO "users" ("name","inserted_at","updated_at") VALUES ($1,$2,$3) RETURNING "id", "activation_key" ["John Doe", {{2016, 8, 4}, {7, 38, 14, 0}}, {{2016, 8, 4}, {7, 38, 14, 0}}]
%MyApp.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
activation_key: "921b1599-fc74-48d7-b74a-b4ce4d8b1333", id: 1,
inserted_at: #Ecto.DateTime<2016-08-04 07:38:14>, name: "John Doe",
updated_at: #Ecto.DateTime<2016-08-04 07:38:14>}
Upvotes: 3