2017-11-30 11 views
1

전자 메일 또는 전화 번호로 변경 집합 유효성 검사를 수행하려고하는데 여기에서 @Dogbert의 OR 변경 집합 기능을 찾았습니다. here - 그러나 OR 유효성 검사 흐름이 올바르게 작동하지 않습니다.Elixir Ecto 변경 집합 또는 유효성 검사

전자 메일이나 전화 확인이 항상 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/[email protected]+/) 
    |> 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 

미리 감사드립니다.

답변

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 || ... 
+0

"else 분기가없고 조건이 false 인 경우 반환 값은 nil입니다." - 고맙습니다 @ 도버트. – benco