JediHelpers. ChangesetHelpers
(jedi_helpers v0.3.1)
Copy Markdown
Normalization and validation helpers for Ecto changesets.
These helpers are intended for schema changeset/2 pipelines that receive
browser form input and need consistent values before persistence.
Summary
Functions
Trims string changes and converts whitespace-only strings to nil by default.
Trims leading and trailing whitespace from one or more string fields.
Validates that at least one of the given fields has a non-blank value.
Functions
@spec normalize_strings(Ecto.Changeset.t(), atom() | [atom()], keyword()) :: Ecto.Changeset.t()
Trims string changes and converts whitespace-only strings to nil by default.
This is useful for optional form fields where whitespace-only input should be
stored as nil. Non-string fields and fields without a change are left alone.
Set :empty_to_nil to false to retain an empty string after trimming.
Use case and result
An optional profile form can store meaningful names while normalizing an
empty email field to nil:
types = %{name: :string, email: :string}
result =
{%{}, types}
|> Ecto.Changeset.cast(%{"name" => " Leia ", "email" => " "},
[:name, :email]
)
|> JediHelpers.ChangesetHelpers.normalize_strings([:name, :email])
result.changes
# => %{email: nil, name: "Leia"}With empty_to_nil: false, whitespace-only input becomes "" instead.
@spec trim_whitespace(Ecto.Changeset.t(), atom() | [atom()], keyword()) :: Ecto.Changeset.t()
Trims leading and trailing whitespace from one or more string fields.
The helper also validates the post-trim length and can attach an Ecto unique constraint. Non-string fields are ignored.
Options
:max- maximum allowed length after trimming; defaults to255.:enforce_unique- addsunique_constraint/3; defaults tofalse.
Use case and result
A registration changeset can normalize a username before validating or inserting it:
types = %{username: :string}
result =
{%{}, types}
|> Ecto.Changeset.cast(%{"username" => " leia "}, [:username])
|> JediHelpers.ChangesetHelpers.trim_whitespace(:username, max: 50)
Ecto.Changeset.get_change(result, :username)
# => "leia"In a schema-backed changeset, pass enforce_unique: true to attach the
database unique constraint after trimming.
When the trimmed value exceeds :max, the result is invalid rather than
truncated:
result =
{%{}, types}
|> Ecto.Changeset.cast(%{"username" => " too-long "}, [:username])
|> JediHelpers.ChangesetHelpers.trim_whitespace(:username, max: 4)
result.valid?
# => false
@spec validate_any_required(Ecto.Changeset.t(), [atom()], keyword()) :: Ecto.Changeset.t()
Validates that at least one of the given fields has a non-blank value.
By default, the error is attached to the first field. Use :error_field and
:message to customize the resulting changeset error.
Use case and result
A contact form can accept either an email address or a phone number:
types = %{email: :string, phone: :string}
result =
{%{}, types}
|> Ecto.Changeset.cast(%{}, [:email, :phone])
|> JediHelpers.ChangesetHelpers.validate_any_required([:email, :phone],
error_field: :email,
message: "email or phone is required"
)
result.valid?
# => false
result.errors[:email]
# => {"email or phone is required", [validation: :required]}If either field contains a value, the changeset remains valid.