在验证

时间:2016-04-28 07:57:29

标签: elixir phoenix-framework

我有一个user,我想确保user至少有first_namelast_namenicknameuser不必包含所有字段。只要一个就足够了。默认代码仅为所有字段提供验证。如何重写它以检查OR而不是AND?

defmodule Vutuv.User do
  use Vutuv.Web, :model

  schema "users" do
    field :first_name, :string
    field :last_name, :string
    field :nickname, :string

    timestamps
  end

  @required_fields ~w(first_name last_name nickname)
  @optional_fields ~w()

  @doc """
  Creates a changeset based on the `model` and `params`.

  If no params are provided, an invalid changeset is returned
  with no validation performed.
  """
  def changeset(model, params \\ :empty) do
    model
    |> cast(params, @required_fields, @optional_fields)
  end
end

1 个答案:

答案 0 :(得分:2)

您必须先将所有字段从@required_fields移至@optional_fields

@required_fields ~w()
@optional_fields ~w(first_name last_name nickname)

然后,在changeset/2中使用自定义验证器:

def changeset(model, params \\ :empty) do
  model
  |> cast(params, @required_fields, @optional_fields)
  |> validate_first_name_or_last_name_or_nickname(params)
end

def validate_first_name_or_last_name_or_nickname(changeset, :empty) do
  changeset
end

def validate_first_name_or_last_name_or_nickname(changeset, _) do
  first_name = get_field(changeset, :first_name)
  last_name = get_field(changeset, :last_name)
  nickname = get_field(changeset, :nickname)

  if first_name || last_name || nickname do
    # No error if any of those 3 are present.
    changeset
  else
    # All the 3 fields are nil.
    message = "first_name or last_name or nickname must be present"
    changeset
    |> add_error(:first_name, message)
    |> add_error(:last_name, message)
    |> add_error(:nickname, message)
  end
end