elixir - Elixir - 将复杂 if 语句的结果分配给变量
问题描述
如何使error
变量始终等于字符串?它几乎在所有情况下都是 nil,并且永远不应该是 nil。在我有一个字符串的所有场景中,我想使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
解决方案
经验法则是您尽量避免在elixirif
中使用嵌套条件语句。一般来说,这是非常反惯用的和代码气味。
有很多更好的方法来处理每个问题:函数子句、模式匹配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_vegan
通过直接与and进行模式匹配,您可能完全不需要第二个参数voted_not_vegan
,但这需要额外的业务领域知识,所以我将把它留作练习。
推荐阅读
- javascript - 为什么这些嵌套的 forEach 循环的行为是这样的?
- yii2 - 如何在 yii2 Yii:t() 中使用位置占位符;
- android - Android - Get text from one textView and set to another with Android Data Binding
- java - 为什么 songName[i]!= null 在它应该是 F 的时候评估为 T
- javascript - 添加到 D3 条形图的最后一个元素未排序
- webpack - Webpack 4:hash 和 contenthash 和 chunkhash,什么时候用哪个?
- flutter - Navigator 在 Flutter 的底部导航栏中重建父页面和目标页面
- reactjs - 反应路由器发送带有参数的 URL
- mongodb - mongodb服务没有启动
- geoserver - 地理服务器使用 EPSG3857(墨卡托投影)发布 worldImage(png 文件)栅格数据