2017-02-13 33 views
2

如何對OR邏輯進行條件驗證,其中我們檢查是否存在2個值中的1個或兩個值都存在。Ecto中的條件驗證需要2個字段中的任何一個

因此,舉例來說,如果我要檢查,以確保emailmobile字段填寫...我希望能夠傳遞一個列表到的validate_required_inclusionfields驗證的至少1列表中的字段不爲空。

def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, [:email, :first_name, :last_name, :password_hash, :role, :birthdate, :address1, :address2, :city, :state, :zip, :status, :mobile, :card, :sms_code, :status]) 
    |> validate_required_inclusion([:email , :mobile]) 
end 


def validate_required_inclusion(changeset, fields, options \\ []) do 

end 

我該如何做這個條件或驗證?

回答

5

這裏有一個簡單的方法。你可以自定義,支持更好的錯誤信息:

def 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 

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

測試與Post模型和|> validate_required_inclusion([:title , :content])

iex(1)> Post.changeset(%Post{}, %{}) 
#Ecto.Changeset<action: nil, changes: %{}, 
errors: [title: {"One of these fields must be present: [:title, :content]", 
    []}], data: #MyApp.Post<>, valid?: false> 
iex(2)> Post.changeset(%Post{}, %{title: ""}) 
#Ecto.Changeset<action: nil, changes: %{}, 
errors: [title: {"One of these fields must be present: [:title, :content]", 
    []}], data: #MyApp.Post<>, valid?: false> 
iex(3)> Post.changeset(%Post{}, %{title: "foo"}) 
#Ecto.Changeset<action: nil, changes: %{title: "foo"}, errors: [], 
data: #MyApp.Post<>, valid?: true> 
iex(4)> Post.changeset(%Post{}, %{content: ""}) 
#Ecto.Changeset<action: nil, changes: %{}, 
errors: [title: {"One of these fields must be present: [:title, :content]", 
    []}], data: #MyApp.Post<>, valid?: false> 
iex(5)> Post.changeset(%Post{}, %{content: "foo"}) 
#Ecto.Changeset<action: nil, changes: %{content: "foo"}, errors: [], 
data: #MyApp.Post<>, valid?: true> 
1

如何:

def validate_required_inclusion(changeset, fields, options \\ []) do 
    if Enum.any?(fields, fn(field) -> get_field(changeset, field) end), 
     do: changeset, 
     else: add_error(changeset, hd(fields), "One of these fields must be present: #{inspect fields}") 
    end 

get_field讓你通過字段更改集接受,既改變(CAST)和非變化,Enum.any?將確保至少有一個領域在那裏。

+0

我喜歡這個,因爲它比其他較短雖然它沒有在放棄它的工作...我將不得不玩它。謝謝! – DogEatDog

+1

如果一個字段已經在模型中並且沒有發生變化,這將不起作用,例如'Post.changeset(%Post {content:「foo」},%{})'將會失敗,因爲儘管'content'存在,'changes'爲空。 – Dogbert

+0

謝謝@Dogbert,很好。我已經更新了答案,儘管它仍然沒有像你的那樣檢查空字段。 – kmptkp

相關問題