为什么Changeset.change在Elixir中跳过验证?

时间:2017-11-30 10:16:53

标签: validation elixir ecto changeset

这是一个用于插入或更新某些数据的简单函数。 如果用户数据已经在db中,我只需更新它,否则我插入一个包含数据的新行。一切正常,但我有验证问题。 变更集定义:

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:name, :surname, :user_id])
    |> validate_required([:name, :surname, :user_id])
    |> unique_constraint(:user_id)
  end

validate_required目前仅在插入期间工作,而不是在更新期间工作。

  def add_or_change(user_id, new_data) do
    data_from_db = data_by_user_id (user_id)
    case data_from_db do
      nil ->
        Data.changeset(%Data{}, new_data)
        |> Repo.insert()

      _ ->
        Changeset.change(data_from_db, new_data)
        |> Repo.update()
    end
  end

如果我尝试插入"" as:name value,我得到一个错误(不能为空)。但是,如果我用""更新现有行? as:name值,changeset不通过验证,我的db更新不正确。如何在Repo.update()??

之前强制进行更改验证

2 个答案:

答案 0 :(得分:1)

根据文档:Ecto.Changeset/2用于内部数据更改,因此它会绕过验证:

  

该函数用于处理应用程序内部的数据。因此,既不执行验证也不执行铸造。这意味着change/2期望更改映射或关键字中的键是原子。

您应该使用Ecto.Changeset.cast/4来应用验证,然后更新它是否有效。

答案 1 :(得分:0)

不要使用它:

    Changeset.change(data_from_db, new_data)

只需运行您已使用的相同功能:

    Data.changeset(data_from_db, new_data)

顺便说一下,你实际上可以大大简化这个功能:

  def add_or_change(user_id, new_data) do
    (data_by_user_id(user_id) || %Data{})
    |> Data.changeset(new_data)
    |> Repo.insert_or_update()
  end