Search code examples
elixirbelongs-toecto

Ecto validate_required on belongs_to when Struct or nil passed


What is the right way to perform validation on Struct with association passed explicitly?

def changeset(model, params \\ %{}) do
  model
  |> cast(params, [:name])
  |> validate_required([:make, :name])
  |> update_change(:name, &String.downcase/1)
  |> unique_constraint(:name, name: :models_name_make_id_index)
end

How I'm going to use it:

changeset(%Model{make: make}, %{....})

Where make can be nil. And I want proper error message instead of:

** (UndefinedFunctionError) function nil.id/0 is undefined or private

Solution

  • Validations are mainly intended for processing user input, not ensuring data consistency. In case you're creating data programatically, validations are not the right tool to guard against programmer errors (in case someone forgot about adding the association) - database constraints are.

    When processing user input for associations, functions like cast_assoc/3 and cast_embed/3 accept the required: true option to enforce the association's presence.

    It might be a good idea to create a function that does the right thing and adds the association, instead of scattering that logic over the controllers (or other places calling the changeset function).