Эликсир - присвоение результата сложного оператора if переменной - PullRequest
0 голосов
/ 25 апреля 2020

Как бы сделать переменную error всегда равной строке? Это ноль почти во всех сценариях ios, и никогда не должно быть ноль. Во всех сценариях ios, где у меня есть строка, я хочу сделать 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 ]

1 голос
/ 25 апреля 2020

Практическое правило: вы должны строго избегать использования вложенного if условного выражения в . Это очень нелогично c и запах кода в целом.

Существует множество лучших способов справиться с любой проблемой: предложения функций, сопоставление с шаблоном, with/1 и т. Д. 1029 *.

Здесь наиболее приемлемый способ решения этой проблемы - придерживаться разбиения условного выражения на набор функциональных предложений с сопоставлением с образцом. Несколько сработало бы нижеприведенные строки.

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 s - чистое зло.


Вы можете избежать необходимости во втором Параметр вообще, путем сопоставления с шаблоном напрямую как voted_vegan, так и voted_not_vegan, но это требует дополнительных знаний в области бизнеса, поэтому я бы оставил это как упражнение.

0 голосов
/ 25 апреля 2020

Каждый возможный поток управления должен возвращать строку:

error =
      if true do
        if !false and true do
          "!false and true"
        else
          "2nd else case"
        end
      else
        "1st else case"
      end
"!false and true"
...