Elixir' if'和'和'没有按预期工作

时间:2017-05-26 04:23:40

标签: elixir ecto elixir-framework

我有这段代码:

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

代码执行使其成为else子句并将其记录到控制台:

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

因此我们可以看到dbShopdbProduct都有一个id,并且代码执行在某种程度上永远不会进入if子句。我的if条款我做错了什么?我想检查它们是否都有id,如果是,请进入if子句。

路由器中的全部功能:

  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

2 个答案:

答案 0 :(得分:1)

您的地图有一个原子:id作为键,而不是字符串"id",因此您的if应为:

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

如果该值保证为非零(如果存在),您还可以将其缩短为:

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

如果密钥不存在,则使用括号语法访问值不会引发错误,而是返回nil,这是Elixir中的虚假值。

答案 1 :(得分:1)

在Elixir中使用if是一种代码气味,并暗示代码可能以更明确的方式重写。在这里,我将使用Kernel.SpecialForms.with/1,而不是:

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

使用:

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