2017-07-15 4 views
0

Je reçois cette erreur en essayant de mettre à jour un enregistrement avec un changeset:Ecto - Mise à jour d'un enregistrement - fonction non définie __changeset __/0

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 

Code:

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 

c'est le ProductShop que je veux mettre à jour:

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}] 

Pourquoi ai-je l'erreur?

mon ProductShop fichier avec changeset:

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 

dans 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 

Répondre

1

fonction de Ecto changeset que vous écrivez dans le schéma, par des œuvres par défaut pour Ecto.Schema, ce qui signifie que cela fonctionne pour les modules avec des schémas définis en eux. Après avoir utilisé cast, il traite de la structure Ecto.Changeset.

Votre code essaie de travailler avec Ecto.Query en fonction changeset, à savoir ici:

product_shop = query |> Ecto.Query.where(s_id: ^sid) 

Vous devez utiliser Repo.one() à la fin d'avoir struct valide ProductShop et vous pouvez l'utiliser en fonction ProductShop.changeset.

Envisagez également de réécrire comment vous voulez récupérer ce product_shop. S'il vous plaît utiliser Repo.get_by:

Repo.get_by(ProductShop, s_id: s_id, p_id: p_id)