在Ecto中对OR的条件验证需要2个字段中的1个

Dog*_*Dog 7 elixir ecto

如何对OR逻辑进行条件验证,我们检查是否存在2个值中的1个或两个值是否存在.

因此,举例来说,如果我要检查,以确保emailmobile字段填写...我希望能够传递一个列表到fieldsvalidate_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
Run Code Online (Sandbox Code Playgroud)

我该如何进行有条件的OR验证?

Dog*_*ert 14

这是一个简单的方法.您可以自定义它以支持更好的错误消息:

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
Run Code Online (Sandbox Code Playgroud)

使用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>
Run Code Online (Sandbox Code Playgroud)