Using Ecto.Changeset.cast without a schema defined

With this minimal struct:

defmodule Auction.Item do
  defstruct [:id, :title, :description, :ends_at]

  def changeset(item, params \\ %{}) do
    item
    |> Ecto.Changeset.cast(params, [:title, :description, :ends_at])
  end
end

the intent is to slowly, gradually introduce/use Ecto.Changeset.

At the first exploratory steps, the following issue is encountered:

iex> item = Auction.list_items() |> hd()
%Auction.Item{ # snip…

iex> Auction.Item.changeset(item)
** (UndefinedFunctionError) function Auction.Item.__changeset__/0 is undefined or private. Did you mean one of:

      * changeset/1
      * changeset/2

    (auction) Auction.Item.__changeset__()
    (ecto) lib/ecto/changeset.ex:429: Ecto.Changeset.cast/4

Ecto 2.2.9 is being used, and looking at

  1. the error message,
  2. the docs and
  3. the code for Ecto.Changeset.cast/4,

I am stuck on understanding what is happening and how to move forward.

The one finding that seems relevant is this comment/answer on SO suggesting that cast might not work without the struct having a schema defined.


I’m trying to better understand how this works and what options are there. My current understanding is that for the Auction.Item defined above, we need to either:

  1. define a schema for the struct
  2. pass in the data argument in the {data, types} format
  3. any other option?

Thanks for your help!

You’re correct in the options you have. Either you need a schema/embedded_schema which generates your struct, or you use schemaless changesets based on {data, types} tuples. You cannot simply supply just a plain struct to changesets, as this is missing the necessary type information for fields.

2 Likes