Elixir/Phoenix 限制参数,例如 Rails 强参数

Elixir/Phoenix restrict params like Rails strong params

我正在制作 API 唯一的 Phoenix 应用程序。我来自 Ruby Rails 背景,请耐心等待。

假设我有一个包含 emailpasswordpassword_hashrole 字段的用户模型。

我需要限制用户输入的 rolepassword_hash 字段,或者将 emailpassword 字段列入白名单。现在任何人都可以POST注册成为管理员:

{
    "user": {
        "email": "test3@test.com",
        "password": "testpw",
        "password_hash": "shouldn't allow user input",
        "role": "admin"
    }
}

这通常是在 Rails 中使用强参数完成的,这将去除未明确指定的字段。

如何使用最佳实践对 Phoenix 进行 restrict/whitelist 参数设置?

这是我在 user_controller:

中的创建方法
  def create(conn, %{"user" => user_params}) do
    changeset = User.registration_changeset(%User{}, user_params)
    ...
    ...
  end

这是我在模型中的架构和变更集,user.ex。我正在关注 this tutorial, it says "we pipe the new changeset through our original one"

  schema "users" do
    field :email, :string
    field :password, :string, virtual: true
    field :password_hash, :string
    field :role, :string

    timestamps()
  end

  def changeset(model, params \ :empty) do
    model
    |> cast(params, ~w(email), [])
    |> downcase_email()
    |> unique_constraint(:email)
    |> validate_format(:email, ~r/@/)
  end

  def registration_changeset(model, params) do
    model
    |> changeset(params)
    |> cast(params, ~w(password), [])
    |> validate_length(:password, min: 6)
    |> put_password_hash()
  end

Phoenix 的 ,但听起来不像我需要的。

我想我可以通过模式匹配来完成这个,但我不确定如何。

实际上代码的行为符合预期,没有保存角色字段。 (我是在控制台中读取请求,而不是实际检查数据库。)

我知道这已经晚了,但这是这种方法:

defmodule MyApp.Utils do
  def strong_params(params, allowed_fields) when is_map(params) do
    allowed_strings = Enum.map(allowed_fields, &Atom.to_string(&1))

    Enum.reduce(params, [], fn {k, v}, acc ->
      key = check_key(k, allowed_strings)
      acc ++ [{key, v}]
    end)
    |> Enum.reject(fn {k, _v} -> k == nil end)
    |> Map.new()
  end

  defp check_key(k, allowed_strings) when is_atom(k) do
    str_key = Atom.to_string(k)

    if str_key in allowed_strings do
      k
    end
  end
  defp check_key(k, allowed_strings) when is_binary(k) do
    if k in allowed_strings do
      String.to_existing_atom(k)
    end
  end
  defp check_key(_, _), do: nil
end

Reference: https://medium.com/@alves.lcs/phoenix-strong-params-9db4bd9f56d8