# `Erabi.Changeset`
[🔗](https://github.com/hattoriai/erabi/blob/v0.1.0/lib/erabi/changeset.ex#L1)

The rules of a picker (`Erabi.Rules`), checked on the server, in an
`Ecto.Changeset`.

    def changeset(task, params) do
      task
      |> cast(params, [:status, :labels])
      |> Erabi.Changeset.validate_choice(:status, [required: true], options: Task.statuses())
      |> Erabi.Changeset.validate_choice(:labels, @label_rules, options: &Labels.existing/1)
    end

It checks the field's value after the cast (an atom of an `Ecto.Enum`,
an integer id, a list for `{:array, _}`), as the form posted it, and
adds at most one error. The error has `validation: :erabi` and `kind:`
(the reason, see `t:Erabi.Rules.error/0`) with what the message needs
(`count`, `value`...), so that `translate_error/1` of a Phoenix app can
translate it.

Options:

  * `:options` - the options the value must be among (unless the rules
    have `create: true`): anything a picker takes, or a function of the
    posted values (texts) that gives the ones that exist, for options
    that come from a search (`&Labels.existing/1` with a query of
    `where: l.name in ^values`). Without it, any value is an option.
  * `:message` - a message for every error, or a map of messages by
    kind (`%{too_many: "three labels at most"}`).

# `messages`

```elixir
@spec messages() :: %{required(atom()) =&gt; String.t()}
```

The default error messages, by kind. They follow Ecto's own, so that an
app's Gettext already has most of them.

    iex> Erabi.Changeset.messages().required
    "can't be blank"

# `validate_choice`

```elixir
@spec validate_choice(
  Ecto.Changeset.t(),
  atom(),
  Erabi.Rules.t() | keyword(),
  keyword()
) ::
  Ecto.Changeset.t()
```

Checks the value of a field against the rules (an `Erabi.Rules` or its
options) and the options. See the moduledoc.

    iex> types = %{labels: {:array, :string}}
    iex> changeset =
    ...>   {%{}, types}
    ...>   |> Ecto.Changeset.cast(%{labels: ["bug", "wontfix"]}, [:labels])
    ...>   |> Erabi.Changeset.validate_choice(:labels, [max: 3], options: ["bug", "feature"])
    iex> changeset.errors
    [labels: {"is not one of the options", [validation: :erabi, kind: :not_allowed, value: "wontfix"]}]

---

*Consult [api-reference.md](api-reference.md) for complete listing*
