I'm new to Elixir, Phoenix and Ecto so I'm following a video tutorial. The tutorial is setting up credentials for users through schemas with each user having one unique credential. So I have a user:
defmodule Foo.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
alias Foo.Accounts.Credential
schema "users" do
field :name, :string
field :username, :string
has_one :credential, Credential
timestamps()
end
@doc false
def changeset(user, attrs) do
user
|> cast(attrs, [:name, :username])
|> validate_required([:name, :username])
|> unique_constraint(:username)
end
end
and a credential:
defmodule Foo.Accounts.Credential do
use Ecto.Schema
import Ecto.Changeset
alias Foo.Accounts.User
schema "credentials" do
field :email, :string
belongs_to :user, User
timestamps()
end
def changeset(credential, attrs) do
credential
|> cast(attrs, [:email])
|> validate_required([:email])
|> unique_constraint(:email)
end
end
The create_user code is:
def create_user(attrs \\ %{}) do
%User{}
|> User.changeset(attrs)
|> Ecto.ChangeSet.cast_assoc(:credential, with: &Credential.changeset/2)
|> Repo.insert()
end
The create credential code is
def create_credential(attrs \\ %{}) do
%Credential{}
|> Credential.changeset(attrs)
|> Repo.insert()
end
When I try to insert a user - with full valid data - I get the error
UndefinedFunctionError at POST /users function Ecto.ChangeSet.cast_assoc/3 is undefined (module Ecto.ChangeSet is not available)
and I don't know why.
The error screen shows Ecto.ChangeSet.cast_assoc/3 Called with 3 arguments #Ecto.Changeset<action: nil, changes: %{name: "jimmyjobber", username: "jimmyjobber"}, errors: [], data: #Foo.Accounts.User<>, valid?: true> :credential [with: &Foo.Accounts.Credential.changeset/2]
and
user %{"email" => "jimmyjobber@emailaddress.com", "name" => "jimmyjobber", "username" => "jimmyjobber"}
From the Ecto docs cast_assoc/3 is used when working with external data.
An extensive search has found articles close to my problem, but nothing that helped.
Please tell me what I have missed so I can move on with this tutorial.
As a previous comment pointed out, the proper name of the module is Ecto.Changeset
-- capitalization matters! Although Elixir is compiled, it still has a bit of runtime flexibility that allows for things like dynamic module names: in other languages, a misspelled module name would be a compile-time error, but in Elixir these are run-time errors (!). (This is by design: it's part of what makes Erlang/Elixir hot-swappable and able to update a running system).
The take-away here is to be very alert to the capitalizations of your module and function names. Any time you get an "undefined" error, triple-check that you have spelled module names correctly.