这是一个简单的方法。您可以对其进行自定义以支持更好的错误消息:
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>