首页 > 解决方案 > Elixir - 在各种 if 子句中附加到元组,但元组不断被重置为空白

问题描述

该代码过去可以工作,能够messages根据各种条款将自定义消息放入其中并将这些消息发送回前端。

我更新了 Elixir。现在messages总是{}将它发送回前端。我该怎么做才能让这个旧代码将消息附加到messages现在?它会附加它们,我会立即检查,它们会在那里。但到最后,里面什么都没有。

我所有其他代码仍然有效,只是messages不再向前端返回任何内容,因为它在函数结束时变为空。这就像 iff 内部的变量范围不一样,它是一个完全不同的变量或其他东西。

defmodule Api.Controllers.PutProductIsVegan do 
  import Api.UserProduct
  alias Api.UserProduct, as: UserProduct
  import Ecto.Query
  import Api.Repo
  import Plug.Conn

  def parse_elem("true"),  do: true
  def parse_elem("false"), do: false

  def put_product_is_vegan(conn) do
    messages = {}
    db_user_product = %{}
    product = Api.Product |> Api.Repo.get(conn.query_params["p_id"])
    vegan_count = product.vegan_count
    not_vegan_count = product.not_vegan_count
    confirm = parse_elem(conn.body_params["confirm"])
    report = parse_elem(conn.body_params["report"])
    IO.inspect(confirm, label: "confirm")
    IO.inspect(report, label: "report")
    uid = conn.query_params["u_id"]
    pid = conn.query_params["p_id"]
    IO.inspect(uid, label: "confirm")
    IO.inspect(pid, label: "report")

    user_product = (from up in Api.UserProduct,
    where: up.u_id == ^uid,
    where: up.p_id == ^pid)
    |> Api.Repo.one
    IO.inspect(user_product)

    if !user_product do
      IO.puts("insert user product")
      UserProduct.insert_user_product(conn, %{
      p_id: String.to_integer(pid), 
      u_id: uid, 
      voted_not_vegan: report,
      voted_vegan: confirm
      })
    end

    user_product = (from up in Api.UserProduct,
    where: up.u_id == ^uid,
    where: up.p_id == ^pid)
    |> Api.Repo.one
    IO.inspect(user_product)

    if !user_product.voted_not_vegan && report do
      IO.puts("add 1 to product.not_vegan_count")
      changeset = Api.Product.changeset(
        product, %{:not_vegan_count => not_vegan_count + 1}
      )
      case Api.Repo.update(changeset) do
        {:ok, product} -> 
          messages = Tuple.append(messages, "Product updated")
        {:error, changeset} -> 
          messages = Tuple.append(messages, "Product not updated")
      end
      IO.puts("set up.voted_not_vegan to true")
      changeset = Api.UserProduct.changeset(
        user_product, %{:voted_not_vegan => true}
      )
      case Api.Repo.update(changeset) do
          {:ok, product} -> 
            messages = Tuple.append(messages, "Product updated")
          {:error, changeset} -> 
            messages = Tuple.append(messages, "Product not updated")
      end
    end

    if !user_product.voted_vegan && confirm do
      IO.puts("add 1 to product.vegan_count")
        changeset = Api.Product.changeset(
          product, %{:vegan_count => vegan_count + 1}
        )
        case Api.Repo.update(changeset) do
          {:ok, product} -> 
            messages = Tuple.append(messages, "Product updated")
          {:error, changeset} -> 
            messages = Tuple.append(messages, "Product not updated")
        end
      IO.puts("set up.voted_vegan to true") 
      IO.inspect (user_product)
      changeset = Api.UserProduct.changeset(
        user_product, %{:voted_vegan => true}
      )

      case Api.Repo.update(changeset) do
          {:ok, product} -> 
            messages = Tuple.append(messages, "Product updated")
          {:error, changeset} -> 
            messages = Tuple.append(messages, "Product not updated")
      end
    end

    conn
      |> put_resp_content_type("application/json")
      |> send_resp(200, Poison.encode!(%{
          successs: "success",
          errors: Tuple.to_list(messages)
      }))
  end
end

编辑

从亚当斯的回答我已经做到了这一点,但最后messages仍然是空白的:

defmodule Api.Controllers.PutProductIsVegan do 
  import Api.UserProduct
  alias Api.UserProduct, as: UserProduct
  import Ecto.Query
  import Api.Repo
  import Plug.Conn

  def parse_elem("true"),  do: true
  def parse_elem("false"), do: false

  def put_product_is_vegan(conn) do
    messages = {}
    db_user_product = %{}
    product = Api.Product |> Api.Repo.get(conn.query_params["p_id"])
    vegan_count = product.vegan_count
    not_vegan_count = product.not_vegan_count
    confirm = parse_elem(conn.body_params["confirm"])
    report = parse_elem(conn.body_params["report"])
    IO.inspect(confirm, label: "confirm")
    IO.inspect(report, label: "report")
    uid = conn.query_params["u_id"]
    pid = conn.query_params["p_id"]
    IO.inspect(uid, label: "confirm")
    IO.inspect(pid, label: "report")

    user_product = (from up in Api.UserProduct,
    where: up.u_id == ^uid,
    where: up.p_id == ^pid)
    |> Api.Repo.one
    IO.inspect(user_product)

    if !user_product do
      IO.puts("insert user product")
      UserProduct.insert_user_product(conn, %{
      p_id: String.to_integer(pid), 
      u_id: uid, 
      voted_not_vegan: report,
      voted_vegan: confirm
      })
    end

    user_product = (from up in Api.UserProduct,
    where: up.u_id == ^uid,
    where: up.p_id == ^pid)
    |> Api.Repo.one
    IO.inspect(user_product)

    if user_product.voted_not_vegan && report do
      messages = Tuple.append(messages, "You have already reported this product")
    end

    if !user_product.voted_not_vegan && report do
      IO.puts("add 1 to product.not_vegan_count")
      changeset = Api.Product.changeset(
        product, %{:not_vegan_count => not_vegan_count + 1}
      )
      messages =
      case Api.Repo.update(changeset) do
        {:ok, product} -> Tuple.append(messages, "Product updated")
        {:error, changeset} -> Tuple.append(messages, "Product not updated")
      end
      IO.puts("set up.voted_not_vegan to true")
      changeset = Api.UserProduct.changeset(
        user_product, %{:voted_not_vegan => true}
      )
      messages =
      case Api.Repo.update(changeset) do
          {:ok, product} -> Tuple.append(messages, "Product updated")
          {:error, changeset} -> Tuple.append(messages, "Product not updated")
      end
    end

    if !user_product.voted_vegan && confirm do
      IO.puts("add 1 to product.vegan_count")
        changeset = Api.Product.changeset(
          product, %{:vegan_count => vegan_count + 1}
        )
        messages =
        case Api.Repo.update(changeset) do
          {:ok, product} -> Tuple.append(messages, "Product updated")
          {:error, changeset} -> Tuple.append(messages, "Product not updated")
        end
      IO.puts("set up.voted_vegan to true") 
      IO.inspect (user_product)
      changeset = Api.UserProduct.changeset(
        user_product, %{:voted_vegan => true}
      )

      messages =
      case Api.Repo.update(changeset) do
          {:ok, product} -> Tuple.append(messages, "Product updated")
          {:error, changeset} -> Tuple.append(messages, "Product not updated")
      end
    end

    IO.inspect(messages) # this is {}

    conn
      |> put_resp_content_type("application/json")
      |> send_resp(200, Poison.encode!(%{
          successs: "success",
          errors: Tuple.to_list(messages)
      }))
  end
end

标签: elixirecto

解决方案


你的问题是在这样的陈述中:

case Api.Repo.update(changeset) do
  {:ok, product} -> 
    messages = Tuple.append(messages, "Product updated")
  {:error, changeset} -> 
    messages = Tuple.append(messages, "Product not updated")
end

尽管您正在分配 to messages,但它的范围仅限于 case 语句中。您实际上是附加到元组,将其分配给一个新的范围变量,该变量也恰好被调用messages,然后丢弃它。然后,您将使用messages = {}when you do的原始声明Tuple.to_list(messages)

您应该能够通过将 case 语句的结果分配给来修复它messages

messages =
  case Api.Repo.update(changeset) do
    {:ok, product} -> Tuple.append(messages, "Product updated")
    {:error, changeset} -> Tuple.append(messages, "Product not updated")
  end

不幸的是,您似乎需要进行大量重组,因为代码在不可变语言中使用了可变编码风格。如果你想重组,你可以这样做:

定义一个接受消息列表并有条件地添加新消息的函数:

def add_message_if(messages, message, true), do: [message | messages]
def add_message_if(messages, _message, false), do: messages

然后你可以像这样在链中调用它:

messages =
[]
|> add_message_if("You have already reported this product", user_product.voted_not_vegan)
|> add_message_if("Product updated", !user_product.voted_not_vegan && updated?)
|> add_message_if("Product not updated", !user_product.voted_not_vegan && !updated?)
...

最后,Enum.reverse(messages),因为我们在消息前面。


推荐阅读