elixir - Phoenix : pattern matching params in contexts (atoms and strings)

标签 elixir phoenix-framework

我有以下函数定义,我正试图找到一种方法来简化参数,使它们都统一。

  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}

与下面的对比,它直接从 Controller 函数中获取参数(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

这些参数与具有字符串键的映射匹配。正如我提到的那样,我这样做是因为这样我就可以直接从 Controller 传递 params 并与传入的内容进行模式匹配(在本例中为各种登录方法)。是否有解决此类问题的标准 Phoenix 方法?

最佳答案

这是一种使用模式匹配的可能解决方案。

这可能不是最漂亮的解决方案,但我认为同时匹配字符串和原子键从来都不是。

  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 映射转换为字符串键(相反,动态生成原子通常被认为是一个坏主意)。

关于elixir - Phoenix : pattern matching params in contexts (atoms and strings),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46588636/

相关文章:

redis - 使用 Redix 或 Exredis 测试 redis 服务器

elixir - Elixir 插件中的版本控制 API

ssh - 通过公共(public) IP 将 erlang observer 连接到远程机器

elixir - Phoenix : Having a JSON and HTML representation of the same resource

elixir - 如何正确地将任意路径重新路由到 Plug.Static 文件的文件?

在 Elixir 中异步运行长时间运行的任务

checkbox - Elixir ExAdmin,如何将 bool 输入定义为复选框?

Javascript:Phoenix channel 立即进入错误状态

灵药/Phoenix : Why do route helpers require @conn?

erlang - 如何在 Phoenix 中获取请求正文?