Elixir Ecto 变更集或验证
Elixir Ecto Changeset OR Validation
我正在尝试对电子邮件或 phone 号码执行变更集验证,并且我在此处 从@Dogbert 找到了一个漂亮的 OR 变更集函数 - 但我无法获得我的 OR 验证流程正常工作。
有人介意快速了解一下为什么电子邮件或 phone 验证总是返回 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
提前致谢!
您没有 return 在 validate_required_inclusion_format
中正确地修改修改后的变更集。在 Elixir 中,块中的最后一个值是它的 return 值。在 if 语句中,其 true 和 false 分支的最后一个值是其 return 值。如果您没有 else 分支且条件为假,则 return 值为 nil
.
这是解决问题的最简单方法:将两个顶级 if
和回退 changeset
return 与 ||
:
连接起来
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
将 returned.
注意:此函数的命名具有误导性。与您在我之前的回答中使用的功能不同,您在这里根本没有使用 fields
。你最好不要将 fields
传递给此函数并调用它类似于 add_email_or_phone_changeset
,例如
if value = get_field(changeset, :email) do
...
end ||
if value = get_field(changeset, :phone) do
...
end || ...
我正在尝试对电子邮件或 phone 号码执行变更集验证,并且我在此处
有人介意快速了解一下为什么电子邮件或 phone 验证总是返回 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
提前致谢!
您没有 return 在 validate_required_inclusion_format
中正确地修改修改后的变更集。在 Elixir 中,块中的最后一个值是它的 return 值。在 if 语句中,其 true 和 false 分支的最后一个值是其 return 值。如果您没有 else 分支且条件为假,则 return 值为 nil
.
这是解决问题的最简单方法:将两个顶级 if
和回退 changeset
return 与 ||
:
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
将 returned.
注意:此函数的命名具有误导性。与您在我之前的回答中使用的功能不同,您在这里根本没有使用 fields
。你最好不要将 fields
传递给此函数并调用它类似于 add_email_or_phone_changeset
,例如
if value = get_field(changeset, :email) do
...
end ||
if value = get_field(changeset, :phone) do
...
end || ...