2017-02-13 13 views
2

Как я могу выполнить условную проверку для логики ИЛИ, где мы проверяем, присутствует ли 1 из 2 значений или оба значения присутствуют.Требуется условная проверка в Ecto для OR - 1 из 2 полей

Так, например, если я хочу, чтобы проверить, чтобы убедиться, что email или в mobile поля заполнены ... Я хочу, чтобы иметь возможность передать список в fields из validate_required_inclusion, чтобы подтвердить, что по крайней мере 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 дает вам поле, принятое множество изменений, как изменился (литый) и не изменился, и Enum.any? будет гарантировать, что по крайней мере одно из полей находится там.

+0

Мне нравится, как это было короче другой, хотя он не работает с удалением его в ... Мне придется поиграть с этим. Спасибо! – DogEatDog

+1

Это не сработает, если поле уже находится в модели, а не в изменениях, например. 'Post.changeset (% Post {content:" foo "},% {})' будет терпеть неудачу, потому что 'changes' пуст, даже если присутствует' content'. – Dogbert

+0

Спасибо @Dogbert, хорошо поймать. Я обновил ответ, хотя он по-прежнему не проверяет наличие пустых полей, как это делает ваш. – kmptkp

 Смежные вопросы

  • Нет связанных вопросов^_^