Issue with validate_length

I posted a comment here and wanted to further discuss

I have an {:array, :map} field which (am converting to embedded as well) I tried using validate_length/3 and when I use a blank record (like %Something{}) the default of [] doesn’t trigger my validate_length/3 call. I tried it on strings as well and its not working on v2.0.5 …

Here are (the important parts) of my schema:

defmodule Chat.Chat do
  use Chat.Web, :model

  schema "chats" do
    embeds_many :messages, Chat.Message
  end

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [])
    |> cast_embed(:messages)
    |> validate_required([:messages])
    |> validate_length(:messages, min: 1)
  end
end
1 Like

When I do %Chat.Chat{} |> Chat.changeset() the returning changeset is valid…

Also, tried on the 2.1.0-rc.3 release candidate as well…

It looks like because of this line:

It will not run the validator unless the field is in the changes. From testing this out (with the rc and 2.0.5), I absolutely cannot get the validate_length/1 to do anything. I tried inserting an empty [] relation, no error. Inserted a single record for the embeds_many and no error (as expected). Tried doing an update to set it back to [] and got the on_replace error talking about orphaning documents.

It looks like EVERY validator now uses validate_change/3… This seems broken to me.

I added this test and it fails… Should I open a PR to add this test?

Every validator always used validate_change, since changesets were introduced. If you want to make a field required and validate a particular form, you need to combine the validation function with validate_required. Making sure a required field is present is the sole responsibility of validate_required - other validation functions are not responsible for this, since it’s already handled there.

1 Like

So I guess the problem may be validate_required does not do anything for an embeds many association. Using it with validate_length of min: 1 does not produce an error as expected.

I believe an embeds_many relation or {:array, _} field will fall into this line: https://github.com/elixir-ecto/ecto/blob/master/lib/ecto/changeset.ex#L1334 and not get validated, when there should be a case for [] just like theres a case for ""

1 Like

cast_embed(changeset, :messages, required: true) did work for me… I just couldn’t get things to work with validate_length/3

2 Likes