(Ecto.ChangeError) xxx 的值 xxx 与类型不匹配:float

(Ecto.ChangeError) value xxx for xxx does not match type :float

我有一个将产品添加到数据库的功能(productmap):

  @derive {Poison.Encoder, only: [:s_id, :p_id]}
  schema "product_shops" do
    field :s_id, :integer
    field :p_id, :integer
    field :not_in_shop_count, :integer
    field :price, :float
  end

  def changeset(product_shop, params \ %{}) do
    product_shop
    |> cast(params, [:s_id, :p_id, :price, :not_in_shop_count])
    |> validate_required([:s_id, :p_id])
    |> unique_constraint(:s_id, name: :unique_product_shop)
  end

  def insert_product_shop(conn, product_id, shop_id, price) do
    IO.inspect(price, label: "price")
    changeset = Api.ProductShop.changeset(%Api.ProductShop{p_id: product_id, s_id: shop_id, not_in_shop_count: 0, price: price})
    errors = changeset.errors
    valid = changeset.valid?
    case insert(changeset) do
      {:ok, product_shop} ->
        {:ok, product_shop}
      {:error, changeset} ->
        {:error, :failure}
    end
  end

IO.inspect显示:

price: 52

但是我得到这个错误:

(Ecto.ChangeError) value `24` for `Api.ProductShop.price` in `insert` does not match type :float

所以价格是 int 但需要是 float

这是来自IO.inspect(product)

的日志
%{"brand" => "if",
  "categories" => [%{"categoryId" => 1, "label" => "Meat",
     "selectedAdd" => true, "selectedSearch" => false, "value" => 1}],
  "description" => "kcjcufujdifgkv. ckcfickc", "name" => "car",
  "not_vegan_count" => 0, "number_of_votes" => 0, "price" => 24,
  "rating" => nil,
  "shop" => %{"latitude" => -37.6739483, "longitude" => 176.1662587,
    "name" => "Rebel Sport", "place_id" => "ChIJgRN1iu_bbW0Rsb-fET0z81Y"}}

将价格转换为浮动尝试(using this resource):

  def insert_product(conn, product) do
  IO.puts("the product price")
  IO.inspect(Map.fetch(product, "price"))
  %{product | "price" => "price" / 1}
  IO.puts("the product price as a float")
  IO.inspect(Map.fetch(product, "price"))

它记录了这个:

the product price
{:ok, 24}

有错误:

** (ArithmeticError) bad argument in arithmetic expression

如何让 map 中的 price 成为 float

回答问题:

iex(1)> map = %{"foo" => 42}
%{"foo" => 42}
iex(2)> %{map | "foo" => map["foo"] / 1}
%{"foo" => 42.0}

请注意,在 Elixir 术语中 都是不可变的 ,因此即使是正确的子句:

%{product | "price" => product["price"] / 1}

是一个 NOOP。结果立即被丢弃。必须重新绑定 product 才能稍后使用它:

product = %{product | "price" => product["price"] / 1}

一般应该用 Ecto.Changeset.cast/4 来完成,而不是明确地。

如果由于某种原因需要手动转换值,Ecto.Type.cast/2 来拯救:

Ecto.Type.cast(:float, 1)
#⇒ 1.0

旁注: IO.inspect/2 接受第二个参数 opts

IO.inspect(product, label: "the product")