我有以下功能定义,我试图找到一种方法来简化参数,使它们全部均匀。
def update_user(%User{} = user, %{password: _} = attrs) do
attrs = Map.put(attrs, :password_reset_token, nil)
update_user(user, attrs, &User.password_changeset/2)
end
def update_user(%User{} = user, %{password_reset_token: _} = attrs), do:
update_user(user, attrs, &User.password_reset_changeset/2)
def update_user(user, attrs), do:
update_user(user, attrs, &User.changeset/2)
def update_user(user, attrs, changeset) do
user
|> changeset.(attrs)
|> Repo.update()
end
程序员可能会把这个弄得一团糟,通过传递一个带有字符串键的地图(例如%{"password" => value}
)并且它与update_user/2
匹配。那么也许我应该更新这些功能的参数?或者使用update_user(user, attrs)
上的警卫与w %{"password" => value}
不匹配?
与以下对比,从控制器函数(def create(conn, params)
)直接获取参数:
def authenticate_user(%{"email" => email, "access_token" => _}) do
case get_by(%{email: email}) do
%User{} = user ->
{:ok, user}
nil ->
{:error, :non_existent}
end
end
def authenticate_user(%{"email" => email, "password" => password}) do
with %User{} = user <- get_by(%{email: email}),
{:ok} <- verify_password(password, user.password_hash),
do: {:ok, user}
end
这些参数与具有字符串键的地图匹配。正如我所提到的那样,我这样做是因为我可以直接从控制器传递params
并且模式匹配传入的内容(在这种情况下,是各种登录方法)。是否有一种标准的凤凰方式来解决这类问题?
答案 0 :(得分:0)
以下是使用模式匹配的一种可能解决方案。
它可能不是最美丽的解决方案,但我认为字符串和原子键都不匹配。
def update_user(%User{} = user, attrs) do
user
|> user_changeset(attrs)
|> Repo.update()
end
def user_changeset(user, attrs) do
case attrs do
%{"password" => _} ->
User.password_changeset(user, Map.put(attrs, "password_reset_token", nil))
%{password: _} ->
User.password_changeset(user, Map.put(attrs, :password_reset_token, nil))
%{"password_reset_token" => _} ->
User.password_reset_changeset(user, attrs)
%{password_reset_token: _} ->
User.password_reset_changeset(user, attrs)
_ ->
User.changeset(user, attrs)
end
end
此外,您可以为所有情况模式匹配函数参数,但我认为在这种情况下更复杂。
另一种选择是首先将所有attrs
映射转换为字符串键(反之,动态生成原子通常被认为是个坏主意)。