Elixir-将复杂的if语句的结果分配给变量

时间:2020-04-25 02:39:03

标签: elixir

如何使error变量始终等于字符串?在几乎所有情况下,它都为零,并且永远不应为零。在所有有字符串的情况下,我都想使error等于该字符串:

error = if user_product do
      if user_product.voted_not_vegan && report do
        "Whoops! You have already reported this product is not vegan"
      end

      if !user_product.voted_not_vegan && report do
        changeset =
        UserProduct.changeset(
          user_product,
          %{:voted_not_vegan => true}
        )
        case Api.Repo.update(changeset) do
          {:ok, product} -> IO.puts("error")
          {:error, changeset} -> IO.puts("error")
        end

        "Success! Reported not vegan"
        changeset =
        Product.changeset(
          product,
          %{:not_vegan_count => not_vegan_count + 1}
        )

        case Api.Repo.update(changeset) do
          {:ok, product} -> IO.puts("error")
          {:error, changeset} -> IO.puts("error")
        end
      end

      IO.inspect(user_product, label: "userproduct")
      IO.inspect(confirm, label: "confirm")

      if user_product.voted_vegan && confirm do
        "Whoops! You have already confirmed this product is vegan"
      end

      if !user_product.voted_vegan && confirm do
        changeset =
        Product.changeset(
          product,
          %{:vegan_count => vegan_count + 1}
        )


        case Api.Repo.update(changeset) do
          {:ok, product_shop} -> IO.puts("error")
          {:error, changeset} -> IO.puts("error")
        end


        "Success! Confirmed is vegan"

        changeset =
        UserProduct.changeset(
          user_product,
          %{:voted_vegan => true}
        )

        case Api.Repo.update(changeset) do
          {:ok, product} -> IO.puts("error")
          {:error, changeset} -> IO.puts("error")
        end
      end
    else
      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
      })

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

      if report do
        changeset =
        Product.changeset(
          product,
          %{:not_vegan_count => not_vegan_count + 1}
        )
        case Api.Repo.update(changeset) do
          {:ok, product} -> IO.puts("error")
          {:error, changeset} -> IO.puts("error")
        end

        changeset =
        UserProduct.changeset(
          user_product,
          %{:voted_not_vegan => true}
        )

        case Api.Repo.update(changeset) do
          {:ok, product} -> IO.puts("error")
          {:error, changeset} -> IO.puts("error")
        end

        "Success! Reported not vegan"

      end

下面是我对@Aleksei Matiushkin的回答的实现。尽管可能已经偏离了答案,但它似乎正在起作用。

  @spec check_user_product(
          usr_prduct :: %UserProduct{},
          {report :: boolean(), confirm :: boolean()},
          product :: %Product{}
        ) :: any()
  defp check_user_product(user_product, report_confirm, product)

  @doc """
    User confirms product is vegan, when they have already done so.
  """
  defp check_user_product(
         %UserProduct{voted_vegan: true} = _usr_prduct,
         {_, true} = _report_confirm,
         _product
       ) do
    "Whoops! You have already confirmed this product is vegan"
  end

  @doc """
    User confirms product is vegan, when they have not already done so.
  """
  defp check_user_product(
         %UserProduct{voted_vegan: false} = usr_prduct,
         {_, true} = _report_confirm,
         product
       ) do
    changeset =
      Product.changeset(
        product,
        %{:vegan_count => product.vegan_count + 1}
      )

    case Api.Repo.update(changeset) do
      {:ok, _} -> IO.puts("filler")
      {:error, _} -> IO.puts("filler")
    end

    changeset =
      UserProduct.changeset(
        usr_prduct,
        %{:voted_vegan => true}
      )

    case Api.Repo.update(changeset) do
      {:ok, _} -> IO.puts("filler")
      {:error, _} -> IO.puts("filler")
    end

    "Success! Confirmed is vegan"
  end

  @doc """
    User reports product is not vegan, when they have already done so.
  """
  defp check_user_product(
         %UserProduct{voted_not_vegan: true} = _usr_prduct,
         {true, _} = _report_confirm,
         _product
       ),
       do: "Whoops! You have already reported this product is not vegan"

  @doc """
    User reports product is not vegan, when they haven't already done so.
  """
  defp check_user_product(
         %UserProduct{voted_not_vegan: false} = usr_prduct,
         {true, _} = _report_confirm,
         product
       ) do
    changeset =
      UserProduct.changeset(
        usr_prduct,
        %{:voted_not_vegan => true}
      )

    case Api.Repo.update(changeset) do
      {:ok, _} -> IO.puts("filler")
      {:error, _} -> IO.puts("filler")
    end

    changeset =
      Product.changeset(
        product,
        %{:not_vegan_count => product.not_vegan_count + 1}
      )

    case Api.Repo.update(changeset) do
      {:ok, _} -> IO.puts("filler")
      {:error, _} -> IO.puts("filler")
    end

    "Success! Reported not vegan"
  end

  def put_product_is_vegan(conn) do
    product = Api.Product |> Api.Repo.get(conn.query_params["p_id"])
    confirm = parse_elem(conn.body_params["confirm"])
    report = parse_elem(conn.body_params["report"])
    uid = conn.query_params["u_id"]
    pid = conn.query_params["p_id"]

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

    user_product =
      if !user_product do
        UserProduct.insert_user_product(conn, %{
          p_id: String.to_integer(pid),
          u_id: uid,
          voted_not_vegan: false,
          voted_vegan: false
        })

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

        user_product
      else
        user_product
      end

    error = check_user_product(user_product, {report, confirm}, product)

    product = Api.Repo.get_by(Product, id: pid)

    IO.inspect(error, label: "errors")

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

2 个答案:

答案 0 :(得分:1)

经验法则是您尝试严格避免在中使用嵌套的if条件语句。一般来说,它极具反习惯和代码异味。

有很多更好的方法来处理每个问题:函数子句,模式匹配,with/1等。

解决此问题的最适用方法是坚持将条件拆分为一组具有模式匹配的函数子句。在下面几行旁边会起作用。

error = check_user_product(user_product, {report, config})

@spec check_user_product(
        up :: %UserProduct{},
        {report :: boolean(), config :: boolean()},
        stage :: :checking_not | :checking_yes
      ) :: any()
defp check_user_product(up, rc, stage \\ :checking_not)

defp check_user_product(
      %UserProduct{voted_not_vegan: true} = up,
      {false, _} = rc,
      :checking_not),
  do: check_user_product(up, rc, :checking_yes)

defp check_user_product(
      %UserProduct{voted_not_vegan: true} = up,
      {true, _},
      :checking_not),
  do: "Whoops! You have already reported this product is not vegan"

defp check_user_product(
      %UserProduct{} = up,
      {true, _},
      :checking_not),
  do: changeset = [...]

defp check_user_product(
      %UserProduct{voted_vegan: true} = up,
      {_, true},
      :checking_yes),
  do: "Whoops! You have already reported this product is vegan"

defp check_user_product(%UserProduct{} = up, _, :checking_yes),
  do: changeset = [...]

defp check_user_product(_, _, _),
  do: "Whoops! No UserProduct"

在这里,我们对%UserProduct{}进行模式匹配以通过投票进行模式匹配,然后立即返回或继续进行下一个检查。

想象一下,如果不确定,输入会遵循模式匹配路径。

嵌套的条件if是纯粹的邪恶。


通过直接与voted_veganvoted_not_vegan进行模式匹配,可以完全避免第二个参数的需要,但这需要对业务领域有更多的了解,因此我将其保留为锻炼。

答案 1 :(得分:-1)

所有可能的控制流都必须返回一个字符串:

ssh::server:options:
profiles::sshd::config:
profiles::sshd::config::ssh::server:
profiles::sshd::config::options:
profiles::sshd::config::ssh::server::options:
相关问题