Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir 为什么在Ecto模型模式中默认值中的函数只计算一次,以及如何修复?_Elixir_Ecto - Fatal编程技术网

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>}