Change in the mix phx.gen.schema generated file

Phoenix 1.3.0 generated the following something.ex file when I ran mix phx.gen.schema MyContext.Something somethings name whatever.

defmodule MyApp.MyContext.Something do
  use Ecto.Schema
  import Ecto.Changeset
  alias MyApp.MyContext.Something


  schema "somethings" do
    field :name, :string
    field :whatever, :string

    timestamps()
  end

  @doc false
  def changeset(%Something{} = something, attrs) do
    something
    |> cast(attrs, [:name, :whatever])
    |> validate_required([:name, :whatever])
  end
end

But now Phoenix 1.3.2 generates the following something.ex file when I ran the same command.

defmodule MyApp.MyContext.Something do
  use Ecto.Schema
  import Ecto.Changeset


  schema "somethings" do
    field :name, :string
    field :whatever, :string

    timestamps()
  end

  @doc false
  def changeset(something, attrs) do
    something
    |> cast(attrs, [:name, :whatever])
    |> validate_required([:name, :whatever])
  end
end

tldr; The Alias for MyContext.Something is removed and the first argument inside changeset function changes from %Something{} = something to something.

When I tested to insert some values from the iex, it behaved like previously, but I wonder what changed under the hood and why?

I’d love if @chrismccord or someone else from the Phoenix core team tell me, how and why this change was made.

Thank you!

I’m not in any way related to the core team, but the only thing changed in your code snippet is that a pattern match on %MyContext.Something{} in changeset/2 has been removed.

1 Like

The new way can accept plain maps to cast and verify them. The older ones needed a strict to generate proper changeset.

1 Like

Not quite plain maps, but a tuple of plain maps {data :: map, types :: map}.

https://hexdocs.pm/ecto/Ecto.Changeset.html#cast/4

From the docs

iex> data = %{title: "hello"}
iex> types = %{title: :string}
iex> changeset = cast({data, types}, %{title: "world"}, [:title])
iex> apply_changes(changeset)
%{title: "world"}

So now changeset can be used like so

# ...
{old_data, types}
|> Something.changeset(attrs)
# ...
2 Likes