Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir-在各种if子句中追加到元组,但元组一直被重置为空白_Elixir_Ecto - Fatal编程技术网

Elixir-在各种if子句中追加到元组,但元组一直被重置为空白

Elixir-在各种if子句中追加到元组,但元组一直被重置为空白,elixir,ecto,Elixir,Ecto,这段代码过去是有效的,能够根据不同的子句将自定义消息放入消息中,并将这些消息发送回前端 我更新了长生不老药。现在,消息在返回前端时总是{}。我现在需要做什么才能让这段旧代码将消息附加到messages?它会附加它们,我会马上检查,它们会在那里。但最后,里面什么都没有 我的所有其他代码仍然有效,只是消息不再向前端返回任何内容,因为它在函数结束时变为空。这就像iff中的变量范围不一样,它是一个完全不同的变量 defmodule Api.Controllers.PutProductIsVegan do

这段代码过去是有效的,能够根据不同的子句将自定义消息放入
消息中
,并将这些消息发送回前端

我更新了长生不老药。现在,
消息
在返回前端时总是
{}
。我现在需要做什么才能让这段旧代码将消息附加到
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
编辑

从Adams的回答中,我已经这样做了,但是
消息
最后仍然是空的:

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

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

actions = %{
  user_product.voted_not_vegan && report => fn messages ->
    ["You have already reported this product" | messages]
  end,

  !user_product.voted_not_vegan && report => fn messages ->
    IO.puts("add 1 to product.not_vegan_count")
    changesets = [
      Api.Product.changeset(
        product, %{not_vegan_count: not_vegan_count + 1}
      ),
      Api.UserProduct.changeset(
       user_product, %{:voted_not_vegan => true}
      )
    ]
    Enum.reduce(changesets, messages, fn 
      {:ok, _} -> ["Product updated" | messages]
      {:error, _} -> ["Product not updated" | messages]
    end)
  end,
  ...
}

actions
|> Enum.reduce([], fn
  {true, reducer}, messages -> reducer.(messages)
  {false, _} -> messages 
end)
|> Enum.reverse()
|> List.to_tuple()
case Api.Repo.update(变更集)do
{:好的,产品}->
messages=Tuple.append(消息,“产品更新”)
{:错误,变更集}->
messages=Tuple.append(消息,“产品未更新”)
结束
尽管您正在分配给
消息
,但它的范围是在case语句中。您实际上是在向元组追加,将其分配给一个新的作用域变量,该变量碰巧也被称为
messages
,然后丢弃它。然后在执行
Tuple.to_list(messages)
时,使用的是原始声明
messages={}

您应该能够通过将case语句的结果分配给
消息

消息=
案例Api.Repo.update(变更集)do
{:好的,product}->Tuple.append(消息,“产品更新”)
{:error,changeset}->Tuple.append(消息,“产品未更新”)
结束
不幸的是,您似乎需要进行大量的重构,因为代码在不可变的语言中使用了可变的编码样式。如果你想重组,你可以这样做:

actions = %{
  user_product.voted_not_vegan && report => fn messages ->
    ["You have already reported this product" | messages]
  end,

  !user_product.voted_not_vegan && report => fn messages ->
    IO.puts("add 1 to product.not_vegan_count")
    changesets = [
      Api.Product.changeset(
        product, %{not_vegan_count: not_vegan_count + 1}
      ),
      Api.UserProduct.changeset(
       user_product, %{:voted_not_vegan => true}
      )
    ]
    Enum.reduce(changesets, messages, fn 
      {:ok, _} -> ["Product updated" | messages]
      {:error, _} -> ["Product not updated" | messages]
    end)
  end,
  ...
}

actions
|> Enum.reduce([], fn
  {true, reducer}, messages -> reducer.(messages)
  {false, _} -> messages 
end)
|> Enum.reverse()
|> List.to_tuple()
定义一个接受消息列表并有条件地添加新消息的函数:

def add_message_if(messages,message,true),do:[message | messages]
def add_message_if(messages,_message,false),do:messages
然后,您可以将其称为这样的链:

actions = %{
  user_product.voted_not_vegan && report => fn messages ->
    ["You have already reported this product" | messages]
  end,

  !user_product.voted_not_vegan && report => fn messages ->
    IO.puts("add 1 to product.not_vegan_count")
    changesets = [
      Api.Product.changeset(
        product, %{not_vegan_count: not_vegan_count + 1}
      ),
      Api.UserProduct.changeset(
       user_product, %{:voted_not_vegan => true}
      )
    ]
    Enum.reduce(changesets, messages, fn 
      {:ok, _} -> ["Product updated" | messages]
      {:error, _} -> ["Product not updated" | messages]
    end)
  end,
  ...
}

actions
|> Enum.reduce([], fn
  {true, reducer}, messages -> reducer.(messages)
  {false, _} -> messages 
end)
|> Enum.reverse()
|> List.to_tuple()
消息=
[]
|>添加消息(如果(“您已报告此产品”),用户(产品。投票(非素食主义者)
|>添加_消息_if(“产品更新”!用户_Product.voted_not_vegan&&updated?)
|>添加_消息_如果(“产品未更新”、!user_Product.voted_未_vegan&&!updated?)
...

最后,
Enum.reverse(messages)
,因为我们正在为消息做预处理。

您的问题是在这样的语句中:

actions = %{
  user_product.voted_not_vegan && report => fn messages ->
    ["You have already reported this product" | messages]
  end,

  !user_product.voted_not_vegan && report => fn messages ->
    IO.puts("add 1 to product.not_vegan_count")
    changesets = [
      Api.Product.changeset(
        product, %{not_vegan_count: not_vegan_count + 1}
      ),
      Api.UserProduct.changeset(
       user_product, %{:voted_not_vegan => true}
      )
    ]
    Enum.reduce(changesets, messages, fn 
      {:ok, _} -> ["Product updated" | messages]
      {:error, _} -> ["Product not updated" | messages]
    end)
  end,
  ...
}

actions
|> Enum.reduce([], fn
  {true, reducer}, messages -> reducer.(messages)
  {false, _} -> messages 
end)
|> Enum.reverse()
|> List.to_tuple()
case Api.Repo.update(变更集)do
{:好的,产品}->
messages=Tuple.append(消息,“产品更新”)
{:错误,变更集}->
messages=Tuple.append(消息,“产品未更新”)
结束
尽管您正在分配给
消息
,但它的范围是在case语句中。您实际上是在向元组追加,将其分配给一个新的作用域变量,该变量碰巧也被称为
messages
,然后丢弃它。然后在执行
Tuple.to_list(messages)
时,使用的是原始声明
messages={}

您应该能够通过将case语句的结果分配给
消息

消息=
案例Api.Repo.update(变更集)do
{:好的,product}->Tuple.append(消息,“产品更新”)
{:error,changeset}->Tuple.append(消息,“产品未更新”)
结束
不幸的是,您似乎需要进行大量的重构,因为代码在不可变的语言中使用了可变的编码样式。如果你想重组,你可以这样做:

actions = %{
  user_product.voted_not_vegan && report => fn messages ->
    ["You have already reported this product" | messages]
  end,

  !user_product.voted_not_vegan && report => fn messages ->
    IO.puts("add 1 to product.not_vegan_count")
    changesets = [
      Api.Product.changeset(
        product, %{not_vegan_count: not_vegan_count + 1}
      ),
      Api.UserProduct.changeset(
       user_product, %{:voted_not_vegan => true}
      )
    ]
    Enum.reduce(changesets, messages, fn 
      {:ok, _} -> ["Product updated" | messages]
      {:error, _} -> ["Product not updated" | messages]
    end)
  end,
  ...
}

actions
|> Enum.reduce([], fn
  {true, reducer}, messages -> reducer.(messages)
  {false, _} -> messages 
end)
|> Enum.reverse()
|> List.to_tuple()
定义一个接受消息列表并有条件地添加新消息的函数:

def add_message_if(messages,message,true),do:[message | messages]
def add_message_if(messages,_message,false),do:messages
然后,您可以将其称为这样的链:

actions = %{
  user_product.voted_not_vegan && report => fn messages ->
    ["You have already reported this product" | messages]
  end,

  !user_product.voted_not_vegan && report => fn messages ->
    IO.puts("add 1 to product.not_vegan_count")
    changesets = [
      Api.Product.changeset(
        product, %{not_vegan_count: not_vegan_count + 1}
      ),
      Api.UserProduct.changeset(
       user_product, %{:voted_not_vegan => true}
      )
    ]
    Enum.reduce(changesets, messages, fn 
      {:ok, _} -> ["Product updated" | messages]
      {:error, _} -> ["Product not updated" | messages]
    end)
  end,
  ...
}

actions
|> Enum.reduce([], fn
  {true, reducer}, messages -> reducer.(messages)
  {false, _} -> messages 
end)
|> Enum.reverse()
|> List.to_tuple()
消息=
[]
|>添加消息(如果(“您已报告此产品”),用户(产品。投票(非素食主义者)
|>添加_消息_if(“产品更新”!用户_Product.voted_not_vegan&&updated?)
|>添加_消息_如果(“产品未更新”、!user_Product.voted_未_vegan&&!updated?)
...

最后,
Enum.reverse(messages)
,因为我们正在准备消息。

您应该从了解Elixir中的一切都是不可变的开始。一切意味着一切。下面的代码

foo = {}
if true, do: foo = Tuple.append(foo, :bar)
不按预期更改外部
foo
。也就是说,初始赋值
messages={}
没有意义,如果条件语句实际上都是noop,那么墙就没有意义了

此外,如果所需的结果类型是元组,则不应使用元组进行缩减,最好使用列表累加器,然后再转换为元组。有点像这样:

actions = %{
  user_product.voted_not_vegan && report => fn messages ->
    ["You have already reported this product" | messages]
  end,

  !user_product.voted_not_vegan && report => fn messages ->
    IO.puts("add 1 to product.not_vegan_count")
    changesets = [
      Api.Product.changeset(
        product, %{not_vegan_count: not_vegan_count + 1}
      ),
      Api.UserProduct.changeset(
       user_product, %{:voted_not_vegan => true}
      )
    ]
    Enum.reduce(changesets, messages, fn 
      {:ok, _} -> ["Product updated" | messages]
      {:error, _} -> ["Product not updated" | messages]
    end)
  end,
  ...
}

actions
|> Enum.reduce([], fn
  {true, reducer}, messages -> reducer.(messages)
  {false, _} -> messages 
end)
|> Enum.reverse()
|> List.to_tuple()
在这里,我们首先构建一个
action\u needed=>action
的映射,然后减少操作,在需要时应用相应的操作

因为我们使用了
reduce
,所以我们在迭代之间保留累加器值,而不是在任何地方重新分配累加器值


有一条经验法则:在99%的情况下,如果你发现自己使用的是有条件的,那么你的做法显然是错误的。

你应该从理解长生不老药中的一切都是不可变的开始。一切意味着一切。下面的代码

foo = {}
if true, do: foo = Tuple.append(foo, :bar)
不按预期更改外部
foo
。也就是说,初始赋值
messages={}
没有意义,如果条件语句实际上都是noop,那么墙就没有意义了

此外,不应使用