Skip to content

Instantly share code, notes, and snippets.

@kerryb
Last active December 13, 2023 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kerryb/883f918dbde8220525d13e550a569a03 to your computer and use it in GitHub Desktop.
Save kerryb/883f918dbde8220525d13e550a569a03 to your computer and use it in GitHub Desktop.
LiveBook demonstrating an Ecto changeset/Phoenix form issue

Changeset/Form issue

Mix.install([
  {:phoenix_live_view, "~> 0.20.1"},
  {:phoenix_ecto, "~> 4.4"}
])

Create a struct

defmodule Person do
  alias Ecto.Changeset

  defstruct name: "", member: true

  def changeset(person, changes \\ %{}) do
    Changeset.cast(
      {person,
       %{
         name: :string,
         member: :boolean
       }},
      changes,
      [:name, :member]
    )
  end
end

The changeset correctly casts strings to booleans:

alias Ecto.Changeset

changeset = %Person{} |> Person.changeset()
IO.inspect(Changeset.fetch_field!(changeset, :member), label: "Default")

changeset = %Person{} |> Person.changeset(%{"member" => "false"})
IO.inspect(Changeset.fetch_field!(changeset, :member), label: "From default to false")

changeset = %Person{} |> Person.changeset(%{"member" => "true"})
IO.inspect(Changeset.fetch_field!(changeset, :member), label: "From default to true")

changeset = %Person{member: true} |> Person.changeset(%{"member" => "false"})
IO.inspect(Changeset.fetch_field!(changeset, :member), label: "From true to false")

changeset = %Person{member: false} |> Person.changeset(%{"member" => "true"})
IO.inspect(Changeset.fetch_field!(changeset, :member), label: "From false to true")

nil

But to_form/1 gets confused when you set a field to the string version of its default:

import Phoenix.Component, only: [to_form: 1]

form = %Person{} |> Person.changeset() |> to_form()
IO.inspect(form[:member].value, label: "Default")

form = %Person{} |> Person.changeset(%{"member" => "false"}) |> to_form()
IO.inspect(form[:member].value, label: "From default to false")

form = %Person{} |> Person.changeset(%{"member" => "true"}) |> to_form()
IO.inspect(form[:member].value, label: "From default to true")

form = %Person{member: true} |> Person.changeset(%{"member" => "false"}) |> to_form()
IO.inspect(form[:member].value, label: "From true to false")

form = %Person{member: false} |> Person.changeset(%{"member" => "true"}) |> to_form()
IO.inspect(form[:member].value, label: "From false to true")

nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment