Search code examples
elixirphoenix-frameworkecto

password_hash in `insert` does not match type :string


In my user context I define a password_hash field of type string:

defmodule Catsdogs.UserContext.User do
use Ecto.Schema
import Ecto.Changeset

@acceptable_roles ["Admin", "Manager", "User"]

schema "users" do
  field :username, :string
  field :password, :string, virtual: true
  field :password_hash, :string
  field :role, :string, default: "User"
end

def get_acceptable_roles, do: @acceptable_roles

@doc false
def changeset(user, attrs) do
  user
   |> cast(attrs, [:username, :password, :role])
   |> validate_required([:username, :password, :role])
   |> validate_inclusion(:role, @acceptable_roles)
   |> put_password_hash()
end

defp put_password_hash(%Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset) do
  change(changeset, password_hash: Pbkdf2.add_hash(password))
end

defp put_password_hash(changeset), do: changeset

end

In my seeds.exs, I create a dummy user

{:ok, _cs} =
Catsdogs.UserContext.create_user(%{
  "password" => "t",
  "role" => "Manager",
  "username" => "manager"
})

Why is it denying my password hash field when adding a user, saying that it does not match type :string, when surely it does?

(Ecto.ChangeError) value `%{password_hash: "$pbkdf2-sha512$160000$XfB4A.b62vcGfH2PpmDw8A$E9MNNWHftlgSJnYSwoc1cbUrsDQy24c.MbRdOLdeDBzwnWEOuFzVZuZW8noci3.H/WWUOuF34AQy9ndYIA/gIA"}` for `Catsdogs.UserContext.User.password_hash` in `insert` does not match type :string

Solution

  • The error message is quite clear though: %{password_hash: "$pbkdf2-sha512$160000$XfB4A.b62vcGfH2PpmDw8A$E9MNNWHftlgSJnYSwoc1cbUrsDQy24c.MbRdOLdeDBzwnWEOuFzVZuZW8noci3.H/WWUOuF34AQy9ndYIA/gIA"} does not match a string. That's because it's a map.

    It looks like you made a small error when using the code from here:

    defp put_pass_hash(%Ecto.Changeset{valid?: true, changes:
        %{password: password}} = changeset) do
      change(changeset, Pbkdf2.add_hash(password)) # <-- CHANGE THIS LINE
    end
    
    defp put_pass_hash(changeset), do: changeset