Ecto 变更集 - 跳过 nil 字段

Ecto changeset - skip nil fields

如何将一个字段添加到 changeset 只有当字段不为 nil 时?如果值为 nil,我不想更新数据库中的值。我需要检查 3 个字段并只更新不为零的字段。

当前代码:

  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

这就是 validate_required/3 的用途。 https://hexdocs.pm/ecto/Ecto.Changeset.html#validate_required/3

您将您的变更集和必填字段列表作为原子传递给它。如果任何指定的字段不存在(即 nil),则会将错误添加到您的变更集中,并且它也将被标记为无效。

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

PS。您不需要像上面那样自己管理错误。错误将自动添加到您位于 changeset.errors.

的变更集中

您可以使用 for 创建一个仅包含模式接受的键且其值不为零的新参数映射,并将其传递给 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