Changesets in Ecto - dynamic required fields

Hello. I’m working with existing code and need to modify a changeset on a schema in order to work for my use case. I need to modify the required fields, however I don’t want to insert in the other two fields that are required in addition to the one I need (I only need to update one variable (e.g. var 2 on the struct and not var1 and var0).

What is the best way to do this? Other code relies on this changeset.

  def changeset(struct, params) do

    required_params = [:var0, :var1, :var2]

    struct
    |> cast(params, required_params)
    |> validate_required(required_params)
    |> validate_length(:var0, is: 10)
    |> validate_var1()
  end

From my research, I came to the conclusion that change instead of cast may be a better option, but I’d like to know if that is the best option and what are the pros / cons.

Comments on best practices are very appreciated as I am new to this language. :slight_smile:

I would create an entire new changeset for this operation…

  def modify_var2_changeset(struct, params) do

    required_params = [:var2]

    struct
    |> cast(params, required_params)
    |> validate_required(required_params)

  end
1 Like

Ecto.Changeset.change/2 is used for internal/trusted data; it doesn’t perform filtering, casting and validation.

Ecto.Changeset.cast/4 is used for external/untrusted data, most commonly data coming from user input.

You are of course not limited to a single changeset function in your Schema; also a changeset function can call other reusable changesets. For example:

def changeset(user, attrs) do
  user
  |> cast(attrs, [:name, :username])
  |> validate_required([:name, :username])
  |> validate_length(:username, min: 1, max: 20)
end

def registration_changeset(user, params) do
  user
  |> changeset(params)
  |> cast(params, [:password])
  |> validate_required([:password])
  |> validate_length(:password, min: 6, max: 100)
  |> put_pass_hash()
end

This is a snippet from the Programming Phoenix 1.4 book.

1 Like