elixirphoenix-frameworkectochangeset

function Ecto.ChangeSet.cast_assoc/3 is undefined (module Ecto.ChangeSet is not available)


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.


Solution

  • 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.