0
votes

How do I add a field to a changeset only if the field is not nil? I don't want to update the value in the database if the value is nil. I need to check 3 fields and only update the ones that are not nil.

current code:

  put "/products" do
    errors = {}
    IO.inspect(conn.body_params)

    product = Api.Product |> Api.Repo.get(conn.query_params["id"])
    IO.inspect(product)

    if conn.body_params["image"] do
      changeset = Api.Product.changeset(product, %{image: conn.body_params["image"]})
    end

    if conn.body_params["description"] do
      changeset = Api.Product.changeset(product, %{description: conn.body_params["description"]})
    end

    if conn.body_params["price"] do
      changeset = Api.Product.changeset(product, %{price: conn.body_params["price"]})
    end
    case Api.Repo.update(changeset) do
      {:ok, product} -> 
        errors = Tuple.append(errors, "Product updated")
      {:error, changeset} -> 
        errors = Tuple.append(errors, "Product not updated")
    end

    conn
      |> put_resp_content_type("application/json")
      |> send_resp(200, Poison.encode!(%{
          successs: "success",
          errors: Tuple.to_list(errors)
      }))
  end
2

2 Answers

2
votes

You can create a new params map with only the keys which the schema accepts and whose value is not nil using for, and pass that to changeset/2:

product = Api.Product |> Api.Repo.get(conn.query_params["id"])
params = for key <- ~w(image description price), value = conn.body_params[key], into: %{}, do: {key, value}
changeset = Api.Product.changeset(product, params)
case Api.Repo.update(changeset) do
  ...
end
0
votes

This is what validate_required/3 is for. https://hexdocs.pm/ecto/Ecto.Changeset.html#validate_required/3

You pass it your changeset and a list of required fields as atoms. If any of the specified fields are not present (ie, nil), then an error will be added to your changeset and it will also be flagged as invalid.

iex> changeset |> validate_required([:field1, :field2, :field3])
%Ecto.Changeset{valid?: false, errors: %{"field1" => ["can't be blank"]}}

PS. you don't need to manage errors yourself as you're doing above. Errors will be automatically added to your changeset at changeset.errors.