Elixir 为什么在Ecto模型模式中默认值中的函数只计算一次,以及如何修复?
我有这样一个模式:Elixir 为什么在Ecto模型模式中默认值中的函数只计算一次,以及如何修复?,elixir,ecto,Elixir,Ecto,我有这样一个模式: 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: t
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
所有新用户都具有相同的UUID。模式中的默认值只计算一次吗?我应该在变更集中实现默认值而不是模式吗?就像@Mick MacCallum所说的那样,
:默认值是在编译时在代码中计算的。如果您使用的是PostgreSQL,则可以通过将数据库中列的默认值更改为默认值来解决此问题。这将使PostgreSQL本身为每个记录生成一个随机UUID值gen\u random\u uuid()
需要PostgreSQL扩展名
生成新的迁移:
$ mix ecto.gen.migration add_default_to_users_activation_key
并将新创建的文件内容替换为:
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
您还应在web/models/user.ex中的字段中添加激活密钥声明
,以便插入后从数据库中读回激活密钥
:
schema "users" do
field :activation_key, Ecto.UUID, read_after_writes: true
end
演示:
iex(1)>%MyApp.User{name:“John Doe”}|>MyApp.Repo.insert!
[调试]查询OK db=9.6ms
在“users”(“name”,“inserted_at”,“updated_at”)中插入值($1,$2,$3),返回“id”,“activation_key”[“John Doe”,{{2016,8,4},{7,38,14,0},{2016,8,4},{7,38,14,0}]
%MyApp.User{{uuuuu meta}:{35; exto.Schema.Metadata,
激活密钥:“921b1599-fc74-48d7-b74a-b4ce4d8b1333”,id:1,
插入地址:#exto.DateTime,名称:“John Doe”,
更新地址:#exto.DateTime}
您可以将类型更改为exto.UUID
,并将:autogenerate
选项设置为true。不是100%确定这是否有效,但值得一试:)我不确定替代方案是什么,但是是的,:default
在编译时进行评估。看到了吗?麦克卡勒姆说得很好。这就是原因!Thx.如果我需要定制UUID生成器怎么办?或者自定义函数生成一些其他值?您必须将其添加到变更集
函数中。见和。
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>}