【问题标题】:Why Changeset.change is skipping validation in Elixir?为什么 Changeset.change 在 Elixir 中跳过验证?
【发布时间】:2017-11-30 10:16:52
【问题描述】:

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

  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

如果我尝试将 "" 作为 :name 值插入,我会得到预期的错误(不能为空白)。但是,如果我使用 "" 作为 :name 值更新现有行,则变更集不会通过验证,并且我的数据库更新不正确。如何在 Repo.update() 之前强制验证更改??

【问题讨论】:

    标签: validation elixir ecto changeset


    【解决方案1】:

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

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

    您应该使用Ecto.Changeset.cast/4 来应用验证,如果有效则更新。

    【讨论】:

      【解决方案2】:

      不要使用这个:

          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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-04
        • 2018-05-07
        • 2016-07-13
        • 2019-03-24
        • 2012-12-02
        • 1970-01-01
        • 1970-01-01
        • 2019-05-14
        相关资源
        最近更新 更多