【问题标题】:Elixir Ecto Changeset OR ValidationElixir Ecto 变更集或验证
【发布时间】:2017-11-30 16:45:08
【问题描述】:

我正在尝试对电子邮件或电话号码执行变更集验证,我在@Dogbert here 找到了一个漂亮的 OR 变更集函数 - 但我无法让我的 OR 验证流程正常工作。

有人介意快速了解一下为什么电子邮件或电话验证总是返回 nil 变更集吗?

  @doc false
  def changeset(%User{} = user, attrs) do
    user
    |> cast(attrs, [:email, :phone])
    |> validate_required_inclusion([:email, :phone])
    |> validate_required_inclusion_format([:email, :phone])
  end

  defp validate_required_inclusion(changeset, fields) do
    if Enum.any?(fields, &present?(changeset, &1)) do
      changeset
    else
      # Add the error to the first field only since Ecto requires a field name for each error.
      add_error(changeset, hd(fields), "One of these fields must be present: #{inspect fields}")
    end
  end

  defp present?(changeset, field) do
    value = get_field(changeset, field)
    value && value != ""
  end

  ## TODO - this doesnt work
  defp validate_required_inclusion_format(changeset, fields) do
    if Enum.member?(fields, :email) do
      value = get_field(changeset, :email)
      if value && value != "" do
        IO.inspect(value, label: "email found: ")
        changeset
        |> email_changeset()
      end
    end
    if Enum.member?(fields, :phone) do
      value = get_field(changeset, :phone)
      if value && value != "" do
        IO.inspect(value, label: "phone found: ")
        changeset
        |> phone_changeset()
      end
    end
    changeset
  end

  defp email_changeset(changeset) do
    changeset
    |> validate_required([:email])
    |> validate_format(:email, ~r/.+@.+/)
    |> unique_constraint(:email)
  end

  defp phone_changeset(changeset) do
    changeset
    |> validate_required([:phone])
    |> valid_phone(:phone)
    |> unique_constraint(:phone)
  end

  defp valid_phone(changeset, field) do
    phone = get_field(changeset, field)
    IO.inspect(phone, label: "phone: ")
    {:ok, phone_number} = ExPhoneNumber.parse(phone, "US")
    IO.inspect(phone_number, label: "ExPhoneNumber: ")
    if ExPhoneNumber.is_valid_number?(phone_number) do
      changeset
    else
      changeset
      |> add_error(field, "Invalid Phone Number")
    end
  end

提前致谢!

【问题讨论】:

    标签: validation elixir ecto


    【解决方案1】:

    您没有在validate_required_inclusion_format 中正确返回修改后的变更集。在 Elixir 中,块中的最后一个值是它的返回值。在 if 语句中,其 true 和 false 分支的最后一个值是它的返回值。如果没有else分支且条件为false,则返回值为nil

    这是解决问题的最简单方法:加入两个顶级 if 和后备 changeset 返回 ||

    defp validate_required_inclusion_format(changeset, fields) do
      if Enum.member?(fields, :email) do
        value = get_field(changeset, :email)
        if value && value != "" do
          IO.inspect(value, label: "email found: ")
          changeset
          |> email_changeset()
        end
      end || # <- note this
      if Enum.member?(fields, :phone) do
        value = get_field(changeset, :phone)
        if value && value != "" do
          IO.inspect(value, label: "phone found: ")
          changeset
          |> phone_changeset()
        end
      end || # <- and this
      changeset
    end
    

    现在,如果不满足第一个或第二个 if 条件,您将获得一个 nil,并评估第三个 if。如果第三个或第四个也不满足,最终的回退changeset 将被返回。


    注意:此函数的命名具有误导性。与您在我之前的回答中使用的功能不同,您在这里根本没有使用fields。你最好不要将fields 传递给这个函数并调用它类似于add_email_or_phone_changeset,例如

    if value = get_field(changeset, :email) do
       ...
    end ||
    if value = get_field(changeset, :phone) do
       ...
    end || ...
    

    【讨论】:

    • "如果没有else分支且条件为false,则返回值为nil。" - 谢谢@Dogbert。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 1970-01-01
    • 1970-01-01
    • 2021-03-30
    • 1970-01-01
    相关资源
    最近更新 更多