1
votes

Ecto 3.2.5, Phoenix 1.4.11, Elixir 1.9.4

I have an Ecto Changeset that looks something like this. I have numerous fields that I would like to run validate_length on all with the same max length.

my_model
|> validate_required(required_fields())
|> validate_length(:field, max: 255)
|> validate_length(:another_field, max: 255)
# More of the same validate_length

Instead of listing one-by-one I also tried something along these lines of this with my Changeset after the piping above, without luck.

Enum.map([:field, :another_field], fn string_field ->
  Ecto.Changeset.validate_length(ch, string_field, max: 255)
end)

validate_length only takes a single field by default, so how can I validate length on multiple fields without a line-by-line validate_length?

1

1 Answers

1
votes

Enum.map/2 would not work because what you actually are to perform would be to reduce changeset on many fields via validation.

Simply declare the normal private function like the below

@spec validate_length_many(
  changeset :: Ecto.Changeset.t(), fields :: [atom()]
) :: Ecto.Changeset.t()
defp validate_length_many(
  %Ecto.Changeset{} = changeset, fields
) when is_list(fields) do
  Enum.reduce(fields, changeset, fn field, changeset ->
    validate_length(changeset, field, max: 255)
  end)
end

and use it as

my_model
|> validate_required(required_fields())
|> validate_length_many(~w[f1 f2]a)

or call Enum.reduce/3 directly (it won’t pipe well because the first argument in the call to Enum.reduce/3 would be a list of fields).

changeset = validate_required(my_model, required_fields())
Enum.reduce([:f1, :f2], changeset, fn field, changeset ->
  validate_length(changeset, field, max: 255)
end) #⇒ changeset