0
votes

I am trying to implement user authentication with the Phoenix web framework on Elixir but stumped by this error.

If I run changeset = Blog.User.changeset(%Blog.User{}) inside iex I get the following error:

** (ArgumentError) unknown field "email" for changeset on 
%Blog.User{__meta__: #Ecto.Schema.Metadata<:built, "users">, email: 
nil, id: nil, inserted_at: nil, is_admin: false, name: nil, password:
nil, password_hash: nil, posts: #Ecto.Association.NotLoaded<association 
:posts is not loaded>, updated_at: nil}
  (ecto) lib/ecto/changeset.ex:1318: Ecto.Changeset.ensure_field_exists!/2
  (ecto) lib/ecto/changeset.ex:1305: anonymous fn/5 in Ecto.Changeset.validate_required/3
  (elixir) lib/enum.ex:1755: Enum."-reduce/3-lists^foldl/2-0-"/3
  (ecto) lib/ecto/changeset.ex:1304: Ecto.Changeset.validate_required/3

Here is my model web/models/user.ex:

defmodule Blog.User do
  use Blog.Web, :model

  schema "users" do
    field :email, :string
    field :name, :string
    field :password, :string, virtual: true
    field :password_hash, :string
    field :is_admin, :boolean, default: false

    has_many :posts, Blog.Post

    timestamps()
  end

  @required_fields ~w(email)
  @optional_fields ~w(name is_admin)
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, @required_fields ++ @optional_fields)
    |> validate_required(@required_fields)
  end
end
2
It's just a wild guess but @required_fields and @optional_fields are lists of strings and perhaps cast or validate_required require a list of atoms.NoDisplayName
@JustMichael You were absolutely right! Thank you!Joseph An
Sure, glad to be of help :)NoDisplayName

2 Answers

3
votes

Just to share an explicit possible solution based on JustMichael and PatNowak's answers/comments, using

@required_fields ~w(some fields)a

instead of

@required_fields ~w(some fields)

results in a list of atoms which validate_required requires, and still seems to work with cast.

2
votes

Ecto.Changeset.cast/3 converts keys to atoms, so for cast you can use strings, but Ecto.Changeset.validate_required/3 has to deal with keys as atoms, so your @required_fields should be list of atoms.

By the way- there should be sigil ~a for that.