Best way to learn, buy an out of date book
There is nothing worse than working through a programming textbook and everything working first time. Sometimes the best way to learn is to see backtraces, and broken stuff all over the place. I’ve been working full time as a programmer for over 10 years and while I’m experienced, if there is a possibility for something to break I seem to find it without fail.
I also systematically go through eBay and pick up older Pragmatic Programmers books because I just love the presentation, they’ve nailed it and every read is just a comfortable. However, my £4 Programming Phoenix book means that I’m about 5 years out of date and so everything doesn’t work first time. But that’s ok, I’m learning and finding out stuff by breaking stuff.
Today it’s working out Ecto changeset. Firstly the cast function was missing, so I needed to add import Ecto.Changeset
defmodule Dungeon.Room do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
schema "rooms" do
field :name, :string
field :x, :integer
field :y, :integer
end
def changeset(model, params \\ :empty) do
model
|> cast(params, ~w[name x y], [])
|> validate_length(:name, min: 1, max: 30)
end
end
And now….
Ecto.CastError at GET /rooms/new
expected params to be a :map, got: `:empty`
It appears that cast takes a :map and we’ve defaulted to :empty and cast is now kicking off :S
I can’t replace it with…
def changeset(model, params \\ %{}) do model
|> cast(params, ~w[name x y], [])
|> validate_length(:name, min: 1, max: 30)
end
…since cast is expecting name, x, or y. Oh right. Ok the fourth argument to cast/4 is optional keys. This will be pretty lame since every empty Room struct will have no name, x, or y. So there’s got to be something else missing here :S
def changeset(model, params \\ %{}) do
model
|> cast(params, [], ~w[name x y])
|> validate_length(:name, min: 1, max: 30)
end
Hmmzzz….
It would appear that my name, x, and y are all empty.
def changeset(model, params \\ %{}) do
model
|> cast(params, ~w[name description x y]a, [])
|> validate_length(:name, min: 1, max: 30)
end
Seems we need a list of atoms rather than strings so.
~w[name x y]a
Ok, queen….I’ll check the Ecto documentation. I can read that too right?
defmodule User do
use Ecto.Schema
import Ecto.Changeset
schema "users" do
field :name
field :email
field :age, :integer
end
def changeset(user, params \\ %{}) do
user
|> cast(params, [:name, :email, :age])
|> validate_required([:name, :email])
|> validate_format(:email, ~r/@/)
|> validate_inclusion(:age, 18..100)
|> unique_constraint(:email)
end
end
OK, looks like this \\ :empty isn’t the right thing to do.