I am making an API only Phoenix app. I come from a Ruby on Rails background, so bear with me.
Say I have a User model with email
, password
, password_hash
, and role
fields.
I need to restrict the role
and password_hash
fields from user input, or whitelist the email
and password
fields. Right now anyone could POST this sign up as an admin:
{
"user": {
"email": "[email protected]",
"password": "testpw",
"password_hash": "shouldn't allow user input",
"role": "admin"
}
}
This is typically accomplished in Rails using strong params, which will strip out fields that are not explicitly specified.
How do I do restrict/whitelist params with Phoenix using best practices?
This is my create method in my user_controller:
def create(conn, %{"user" => user_params}) do
changeset = User.registration_changeset(%User{}, user_params)
...
...
end
And here is my schema and changesets in the model, user.ex. I'm following 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's scrub_params is close, but it doesn't sound like what I need.
I think I can accomplish this by pattern matching but I'm not sure how.
cast
is not working, because it should do exactly what you're asking: only allowing theemail
parameter. Also, your controller is usingUser.registration_changeset/2
, but you're showing us the code forUser.changeset/2
. – tompaveregistration_changeset
look like? Yourchangeset
should already be ignoring therole
field inparams
. – Dogbertcast/3
overcast/4
, as the latter is deprecated. – tompave