如何在Ecto中添加互斥约束?

时间:2018-04-29 09:43:04

标签: elixir ecto

我有一个包含两个字段ab的架构,我想要一个字段。也就是说,如果提供ab不应该,反之亦然。

有没有办法通过Ecto变更集验证来优雅地表示这一点?像这样:

schema "foo" do
  field(:a, :string)
  field(:b, :string)
  field(:c, :string)

  timestamps()
end

def changeset(transaction, attrs) do
  transaction
  |> cast(attrs, [:a, :b, :c])
  |> validate_required([:c])
  |> validate_mutual_exclusion([:a, :b])
end

defp validate_mutual_exclusion(changeset, fields) do
  # What goes here?
end

1 个答案:

答案 0 :(得分:1)

您可以计算存在的字段数,并检查是否等于1:

defp validate_mutual_exclusion(changeset, fields) do
  present = Enum.count(fields, fn field -> present?(get_field(changeset, field)) end)

  case present do
    1 -> changeset # ok
    _ ->
      # add an error to each field
      Enum.reduce(fields, changeset, fn field, changeset ->
        add_error(changeset, field, "exactly one of these must be present: #{inspect(fields)}")
      end)
  end
end

present?只检查值是""还是nil

def present?(nil), do: false
def present?(""), do: false
def present?(_), do: true