尝试使用变更集更新记录时出现此错误:
14:36:29.972 [error] #PID<0.341.0> running Api.Router terminated
Server: 192.168.20.3:4000 (http)
Request: PUT /products/?p_id=11&s_id=11
** (exit) an exception was raised:
** (UndefinedFunctionError) function Ecto.Query.__changeset__/0 is undefined or private
(ecto) Ecto.Query.__changeset__()
(ecto) lib/ecto/changeset.ex:422: Ecto.Changeset.do_cast/4
(api) lib/api/product_shop.ex:17: Api.ProductShop.changeset/2
(api) lib/api/router.ex:168: anonymous fn/1 in Api.Router.do_match/4
(api) lib/api/router.ex:1: Api.Router.plug_builder_call/2
(api) lib/plug/debugger.ex:123: Api.Router.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /Users/Ben/Development/Projects/vepo/api/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protoco
l.execute/4
代码:
pid = conn.query_params["p_id"]
sid = conn.query_params["s_id"]
price = conn.query_params["price"]
query = ProductShop |> Ecto.Query.where(p_id: ^pid)
product_shop = query |> Ecto.Query.where(s_id: ^sid)
changeset2 = Api.ProductShop.changeset(product_shop, %{price: price})
case Api.Repo.update(changeset2) do
{:ok, product_shop} ->
errors = Tuple.append(errors, "Price updated")
{:error, changeset2} ->
errors = Tuple.append(errors, "Price not updated")
end
这是我要更新的ProductShop:
14:38:56.658 [debug] QUERY OK source="product_shops" db=1.7ms
SELECT p0."id", p0."s_id", p0."p_id", p0."not_in_shop_count", p0."price" FROM "product_shops" AS p0 []
[%Api.ProductShop{__meta__: #Ecto.Schema.Metadata<:loaded, "product_shops">,
id: 11, not_in_shop_count: 0, p_id: 11, price: 5.99, s_id: 11}]
为什么我收到错误?
带有变更集的 ProductShop 文件:
defmodule Api.ProductShop do
use Ecto.Schema
import Ecto.Changeset
import Api.Repo
import Ecto.Query
@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])
|> 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
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
def delete_all_from_product_shops do
from(Api.ProductShop) |> delete_all
end
def get_product_shops do
Api.ProductShop |> all
end
end
router.ex 中的
put "/products" do
errors = {}
IO.inspect(conn.body_params)
product = Api.Product |> Api.Repo.get(conn.query_params["p_id"])
shop = Api.Shop |> Api.Repo.get(conn.query_params["s_id"])
params = for key <- ~w(image description), value = conn.body_params[key], into: %{}, do: {key, value}
changeset = Api.Product.changeset(product, params)
case Api.Repo.update(changeset) do
{:ok, product} ->
errors = Tuple.append(errors, "Product updated")
{:error, changeset} ->
errors = Tuple.append(errors, "Product not updated")
end
pid = conn.query_params["p_id"]
sid = conn.query_params["s_id"]
price = conn.query_params["price"]
query = ProductShop |> Ecto.Query.where(p_id: ^pid)
product_shop = query |> Ecto.Query.where(s_id: ^sid)
changeset2 = Api.ProductShop.changeset(product_shop, %{price: price})
case Api.Repo.update(changeset2) do
{:ok, product_shop} ->
errors = Tuple.append(errors, "Price updated")
{:error, changeset2} ->
errors = Tuple.append(errors, "Price not updated")
end
IO.inspect(errors)
conn
|> put_resp_content_type("application/json")
|> send_resp(200, Poison.encode!(%{
successs: "success",
errors: Tuple.to_list(errors)
}))
end
答案 0 :(得分:1)
您在架构中编写的Ecto的changeset
函数默认适用于Ecto.Schema
,这意味着它适用于具有已定义架构的模块。使用cast
后,它处理Ecto.Changeset结构。
您的代码尝试在变更集功能中使用Ecto.Query
,即:
product_shop = query |> Ecto.Query.where(s_id: ^sid)
您应该在末尾使用Repo.one()
来拥有有效的ProductShop结构,然后您可以在ProductShop.changeset
函数中使用它。
另请考虑重写您想要检索此product_shop的方式。请使用Repo.get_by
:
Repo.get_by(ProductShop, s_id: s_id, p_id: p_id)