我正在使用一堆可选字段对变更集进行加密,但是我目前正在使用大量的If语句来查看变更集是否包含字段,然后再尝试对其进行加密。
我感觉到有一个Enum函数(如reduce)可以以一种比普通Elixir更好的方式实现此目的,但是我想出的所有方法都没有比一堆丑陋的If语句更有效。 / p>
def encrypt(changeset) do
if changeset.changes["address"] do
{:ok, encrypted_address} = EncryptedField.dump(changeset.changes.address, key_id)
changeset
|> put_change(:address, encrypted_address)
end
if changeset.changes["dob"] do
{:ok, encrypted_dob} = EncryptedField.dump(changeset.changes.dob, key_id)
changeset
|> put_change(:address, encrypted_dob)
end
if changeset.changes["email"] do
{:ok, encrypted_email} = EncryptedField.dump(changeset.changes.email, key_id)
changeset
|> put_change(:email, encrypted_email)
end
...
end
答案 0 :(得分:4)
您需要做的是遍历字段,有条件地更新变更集:
def encrypt(changeset) do
Enum.reduce(~w[address dob email]a, changeset, fn field, changeset ->
if changeset.changes[field] do
{:ok, encrypted} =
EncryptedField.dump(changeset.changes[field], key_id)
put_change(changeset, field, encrypted)
else
changeset # unlike your implementation this works
end
end)
end
另一种方法是首先Enum.filter/2
个字段:
def encrypt(changeset) do
~w[address dob email]a
|> Enum.filter(&changeset.changes[&1])
|> Enum.reduce(changeset, fn field, changeset ->
{:ok, encrypted} =
EncryptedField.dump(changeset.changes[field], key_id)
put_change(changeset, field, encrypted)
end)
end
侧注:根据核心团队的样式准则,如果且链中只有很多链接,则应使用管道。
回答第二个答案:
使用with
的惯用代码为:
def encrypt(changeset) do
~w[address dob email] |> Enum.reduce(changeset, fn field ->
with %{^field => value} <- changeset.changes,
{:ok, encrypted} <- EncryptedField.dump(value, key_id)
do
put_change(changeset, field, encrypted)
else
_ -> changeset
end
end)
end
答案 1 :(得分:1)
同意Aleksei的回答。
长生不老药的另一种模式是,如果在运行表达式之前进行了一系列检查,则可以使用with
。
使用with
的Aleksei的代码类似于
def encrypt(changeset) do
~w[address dob email] |> Enum.reduce(changeset, fn field ->
with \
true <- Map.has_key?(changeset.changes, field),
{:ok, encrypted} <- EncryptedField.dump(changeset.changes[field], key_id)
do
put_change(changeset, field, encrypted)
else
_ -> changeset
end
end)
end
在这里,如果EncryptedField.dump
返回一个:error
,则返回{changeset}而不是抛出{:ok, val} = EncryptedField.dump(...)
时引发异常。
P.S:还建议使用Map.has_key?