由于在虚拟字段上进行验证,因此更新用户时出错

时间:2019-08-03 12:37:55

标签: elixir phoenix-framework

在将数据插入数据库后,由于对两个虚拟字段(:password和:password_confirmation)进行必需的验证(在更新过程中不需要),我发现很难更新记录。我仅在创建用户时需要此字段。

我尝试删除对这些字段的验证,但是由于这个原因,我无法在创建用户时验证数据。

用户架构

defmodule TodoBackend.User.Model.User do
  use Ecto.Schema
  import Ecto.Changeset
  import Argon2, only: [hash_pwd_salt: 1]

  schema "users" do
    field :email, :string
    field :name, :string
    field :phone, :string
    field :password_hash, :string
    # Virtual fields:
    field :password, :string, virtual: true
    field :password_confirmation, :string, virtual: true

    timestamps()
  end

  @doc false
  def changeset(user, attrs) do
    user
    |> cast(attrs, [:email, :name, :phone, :password, :password_confirmation])
    |> validate_required([:email, :name, :phone, :password, :password_confirmation])
    |> validate_format(:email, ~r/@/) # Check that email is valid
    |> validate_length(:password, min: 8) # Check that password length is >= 8
    |> validate_confirmation(:password) # Check that password === password_confirmation
    |> unique_constraint(:email)
    |> put_password_hash
  end

  defp put_password_hash(changeset) do
    case changeset do
      %Ecto.Changeset{valid?: true, changes: %{password: pass}}
        ->
          put_change(changeset, :password_hash, Argon2.hash_pwd_salt(pass))
      _ ->
          changeset
    end
  end

end

用于更新用户的用户控制器功能

  def update(conn, %{"id" => id, "user" => user_params}) do
    user = UserRepo.get_user!(id)

    IO.inspect(user)

    with {:ok, %User{} = user} <- UserRepo.update_user(user, user_params) do
      render(conn, "show.json", user: user)
    end
  end

Ecto回购定义

  def update_user(%User{} = user, attrs) do
    user
    |> User.changeset(attrs)
    |> Repo.update()
  end

实际结果:我收到此错误{“错误”:{“密码”:[“不能为空”],“密码确认”:[“不能为空”]}}

预期结果:我希望验证仍然存在,并且仅应更新指定的字段

1 个答案:

答案 0 :(得分:0)

您可以具有多个变更集功能。

def changeset(user, attrs) do
  user
  |> cast(attrs, [:email, :name, :phone])
  |> validate_required([:email, :name, :phone])
  |> validate_format(:email, ~r/@/) # Check that email is valid
  |> unique_constraint(:email)
end

def registration_changeset(struct, params) do
  struct
  |> changeset(params)
  |> cast(attrs, [:password, :password_confirmation])
  |> validate_required([:password, :password_confirmation])
  |> validate_length(:password, min: 8)
  |> validate_confirmation(:password)
  |> put_password_hash()
end

请注意registration_changeset如何引用changeset。这只是您如何进行设置的一个示例。您可以根据需要拥有多个变更集。毕竟它们只是功能!