2017-05-26 1 views
0

ich diesen Code haben:Elixir ‚wenn‘ und ‚und‘ nicht wie erwartet funktioniert

if Map.has_key?(dbShop, "id") && Map.has_key?(dbProduct, "id") do 
    case Api.Repo.insertProductShop(conn, dbShop.id, dbProduct.id) do 
    {:ok, productShop} -> 
     {:ok, productShop} 
    {:error, changeset} -> 
     Tuple.append(errors, "could not insert product in the Shop") 
    end 
else 
    IO.puts("(dbShop, id) && Map.has_key?(dbProduct, id) failed") 
    IO.inspect(dbShop) 
    IO.inspect(dbProduct) 
end 

Codeausführung in die der else Klausel macht und die Protokolle diese an die Konsole:

(dbShop, id) && Map.has_key?(dbProduct, id) failed 
%Api.Shop{__meta__: #Ecto.Schema.Metadata<:loaded, "shops">, id: 23, 
latitude: -36.846691, longitude: 174.7745803, name: "Yard Bar & Eatery", 
placeId: "ChIJp6DGbAdIDW0RcbnExyPHvCk"} 
%Api.Product{__meta__: #Ecto.Schema.Metadata<:loaded, "products">, 
brand: "baba", description: " zhzngshshhshs", id: 34, image: "no-image", 
name: "Nsn", numberOfVotes: nil, rating: nil} 

So können wir sehen, dass dbShop und dbProduct beide eine id haben und irgendwie die Codeausführung macht es nie in die if Klausel. Was mache ich falsch mit meiner if Klausel? Ich möchte überprüfen, dass sie beide eine id haben und wenn ja, gehen Sie in die if Klausel.

Volle Funktion im Router:

post "/products" do 
    errors = {} 
    postedProduct = conn.body_params 
    dbProduct = %{} 
    dbShop = %{} 
    case Api.Repo.insertProduct(conn, postedProduct) do 
     {:success, product} -> 
     dbProduct = product 
     case Api.Repo.insertProductCategories(conn, postedProduct, dbProduct.id) do 
      {:ok, categories} -> 
      {:ok, categories} 
      {:error, failed_operation, failed_value, changes_so_far} -> 
      Tuple.append(errors, "could not insert productCategories. Product already has that category") 
     end 
     {:error, changeset} -> 
     IO.puts("product not inserted") 
     Tuple.append(errors, "could not insert product. Product already existed") 
     IO.inspect(errors) 
    end 

    if Map.has_key?(postedProduct, "shop") do 
     case Api.Repo.insertShop(conn, postedProduct["shop"]) do 
     {:ok, shop} -> 
      dbShop = shop 
      if Map.has_key?(dbShop, :id) && Map.has_key?(dbProduct, :id) do 
      case Api.Repo.insertProductShop(conn, dbShop.id, dbProduct.id) do 
       {:ok, productShop} -> 
       {:ok, productShop} 
       {:error, changeset} -> 
       Tuple.append(errors, "could not insert product in the Shop") 
      end 
      else 
      IO.puts("(dbShop, id) && Map.has_key?(dbProduct, id) failed") 
      IO.inspect(dbShop) 
      IO.inspect(dbProduct) 
      end 
     {:error, changeset} -> # shop already exists 
      # Tuple.append(errors, "could not insert shop") 
      if Map.has_key?(dbShop, "id") && Map.has_key?(dbProduct, "id") do 
      case Api.Repo.insertProductShop(conn, dbShop.id, dbProduct.id) do 
       {:ok, productShop} -> 
       {:ok, productShop} 
       {:error, changeset} -> 
       Tuple.append(errors, "The product has already been added to the shop") 
      end 
      end 
     end 
    end 

    if tuple_size(errors) > 0 do 
     IO.puts("errors") 
     IO.inspect(errors) 
     conn 
     |> put_resp_content_type("application/json") 
     |> send_resp(200, Poison.encode!(%{ 
      successs: "success", 
      errors: errors 
     })) 
    else 
     conn 
     |> put_resp_content_type("application/json") 
     |> send_resp(200, Poison.encode!(%{ 
      successs: "success" 
     })) 
    end 
    end 
+1

Ihre Schlüssel-Atome sind. Versuchen Sie 'Map.has_key? (...,: id)'. – Dogbert

+0

Was machst du mit diesem Ausdruck? Wenn diese beiden Werte immer Shop- und Product-Strukturen sind, haben sie immer den Schlüssel ': id', selbst wenn der Wert von': id'nil oder false ist. – Dogbert

+0

@Dogbert Danke! Ich dachte, da es nicht ':' vor der 'ID' hatte, war es kein Atom. In Bezug auf Ihren zweiten Kommentar wird 'dbProduct' nur gefüllt, wenn das Produkt in die Datenbank eingefügt wird. Wenn es nicht aufgefüllt wurde, befindet es sich höchstwahrscheinlich bereits in der Datenbank (eindeutige Einschränkung). – BeniaminoBaggins

Antwort

1

Ihre Karte ein Atom :id als Schlüssel hat, nicht die Zeichenfolge "id", so sollten Sie Ihre if sein:

if Map.has_key?(dbShop, :id) && Map.has_key?(dbProduct, :id) do 

Wenn der Wert garantiert sein Nicht-Null, falls vorhanden, können Sie dies auch verkürzen zu:

if dbShop[:id] && dbProduct[:id] do 

Der Zugriff auf einen Wert mit der Klammer-Syntax führt nicht zu einem Fehler, wenn der Schlüssel nicht vorhanden ist, und gibt stattdessen nil zurück, was ein falscher Wert in Elixir ist.

1

Verwenden von if in Elixir ist ein Code-Geruch und ein Hinweis, dass der Code in expliziter Weise neu geschrieben werden könnte. Hier würde ich gehen mit Kernel.SpecialForms.with/1, und statt:

if Map.has_key?(dbShop, :id) && Map.has_key?(dbProduct, :id) do 
    # true 
else 
    # false 
end 

Verwendung:

with %{id: shopId} when not is_nil(shopId) <- dbShop, 
    %{id: prodId} when not is_nil(prodId) <- dbProduct do 
    # true 
else 
    ^dbProduct -> IO.puts "prodId is nil" 
    ^dbShop -> IO.puts "shopId is nil" 
end 
Verwandte Themen