Ecto Changeset, required fields not validating on changes

1.7k Views Asked by At

learning Elixir/Ecto, and have hit a snag related to changesets. Not sure what I'm doing wrong.

I have a "domain model" struct that has some required fields. When I do a put_change, the returned changeset is still saying there's an error on the changeset (field missing), even though it is right there in the changes.

cset = Activity.changeset(%Activity{}, %{details: "Played in the snow", child_id: child_id}) 

#Ecto.Changeset<action: nil,
 changes: %{child_id: "ed553c30-38d2-4cb1-9029-eb2180c141cc",
   details: "Played in the snow"},
 errors: [relevant_date: {"can't be blank", [validation: :required]},
  display_time: {"can't be blank", [validation: :required]}],
 data: #MyApp.Domain.Activity<>, valid?: false> 

The above is to be expected. both relevant_date and display_time are missing, and as such the errors should be there.

cset |> Ecto.Changeset.put_change(:relevant_date, ~D[2016-12-31])

#Ecto.Changeset<action: nil,
 changes: %{child_id: "ed553c30-38d2-4cb1-9029-eb2180c141cc",
   details: "Played in the snow", relevant_date: ~D[2016-12-31]},
 errors: [relevant_date: {"can't be blank", [validation: :required]},
  display_time: {"can't be blank", [validation: :required]}],
 data: #Kidgenius.Domain.Activity<>, valid?: false>

This is the part that doesn't make any sense to me. relevant_date is right there on the changes field, and yet it's still telling me that relevant_date can't be blank.

Any help would be appreciated!

EDIT: This is Ecto 2.1.1.

1

There are 1 best solutions below

2
On BEST ANSWER

put_change doesn't perform validation, you need to pass updated changeset through validate_required, so it will try to perform validation on your updated state.

Hope that clarifies the problem a bit!

EDIT

Just for clarification:

# 1.
cset =
  Activity.changeset(
    %Activity{},
    %{details: "Played in the snow", child_id: child_id}
  )

# 2.
cset = Ecto.Changeset.put_change(cset, :relevant_date, ~D[2016-12-31])

# 3. This probably is something you currently have implemented
#    in your `Activity.changeset`, most likely as second setep
#    after `Ecto.cast/3`.
cset = Ecto.Changeset.validate_required(cset, [:relevant_date])