1
votes

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" => "[email protected]", "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.

1
There is no such module as Ecto.ChangeSet, the name is Ecto.Changeset, you can notice that by looking at the import in your schema module.Daniel
Daniel, Thank you for that. In all my code checking case sensitivity got missed.user2238003

1 Answers

1
votes

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.