Logo

dev-resources.site

for different kinds of informations.

ecto's cast/4 function explained

Published at
5/20/2024
Categories
elixir
phoenix
ecto
webdev
Author
senyeezus
Categories
4 categories in total
elixir
open
phoenix
open
ecto
open
webdev
open
Author
9 person written this
senyeezus
open
ecto's cast/4 function explained

The typical changeset in Ecto is created via the cast/4function.

cast(data, params, permitted, opts \\ [])
Enter fullscreen mode Exit fullscreen mode

I've hardly found its usage intuitive.

def register_user(attrs) do
  %User{}
  |> User.registration_changeset(attrs)
  |> Repo.insert()
end

def registration_changeset(user, attrs, opts \\ []) do
  user
  |> cast(attrs, [:email, :password])
  |> validate_email(opts)
  |> validate_password(opts)
end
Enter fullscreen mode Exit fullscreen mode

Why are we casting with an empty User? What do we actually use attrs for?

As it turns out, it's not even mildly confusing. The purpose of the cast/4 function is as the name says on the box: to cast data from one type into the other. It's necessary as we may receive data from external sources with the wrong type i.e an integer sent as a string from a form. Keep in mind though, we're still dealing with a changeset, whose sole purpose is to track changes to fields in our data.

Per the function signature, cast/4 casts the fields of params into the expected types specified by data, while tracking changes to the data. The only changes that are tracked are those specified by the atoms passed via permitted.

Take this Ecto schema

defmodule User do
  use Ecto.Schema
  import Ecto.Changeset

  schema "users" do
    field :age, :integer
  end
end
Enter fullscreen mode Exit fullscreen mode

And say we do this

iex> changeset = Ecto.Changeset.cast(%User{}, %{age: "0"}, [:age]) 
Enter fullscreen mode Exit fullscreen mode

The parameter age is a string. The cast/4 function will convert it into an integer. And since we've passed in an empty User, we'll get a changeset reflecting the changes we've made i.e adding a parameter age with the value of 0.

iex> changeset
#Ecto.Changeset<
  action: nil,
  changes: %{age: 0}, # type is cast to an integer
  errors: [],
  data: #User<>,
  valid?: true
>
Enter fullscreen mode Exit fullscreen mode

We'll see this fail if our data cannot be converted into an integer with no changes applied.

iex> changeset = Ecto.Changeset.cast(%User{}, %{age: "a"}, [:age]) 
iex> changeset
#Ecto.Changeset<
  action: nil,
  changes: %{},
  errors: [age: {"is invalid", [type: :integer, validation: :cast]}],
  data: #User<>,
  valid?: false
>
Enter fullscreen mode Exit fullscreen mode

If we already have a populated User type and we pass in valid data, we get our change tracking as expected and the data is cast if need be.

iex> changeset = Ecto.Changeset.cast(%User{age: 24}, %{age: "0"}, [:age]) 
iex> changeset
#Ecto.Changeset<
  action: nil,
  changes: %{age: 0},
  errors: [],
  data: #User<>,
  valid?: true
>
Enter fullscreen mode Exit fullscreen mode

More writing

For more of my writing, check out my newsletter: off the wire

phoenix Article's
30 articles in total
Favicon
Pseudolocalization in Phoenix with gettext_pseudolocalize
Favicon
Unlocking the Power of Elixir Phoenix and Rust: A Match Made for High-Performance Web Applications
Favicon
Sql commenter with postgrex
Favicon
Phoenix LiveView is slot empty?
Favicon
Bridging the Gap: Simplifying Live Component Invocation in Phoenix LiveView
Favicon
Find and Fix N+1 Queries Using AppSignal for a Phoenix App in Elixir
Favicon
Managing Distributed State with GenServers in Phoenix and Elixir
Favicon
Complete Guide: Setting up VS Code for Elixir and Phoenix Development
Favicon
A Complete Guide to Phoenix for Elixir Monitoring with AppSignal
Favicon
Better LiveView Hooks with Typescript
Favicon
Scaling Your Phoenix App in Elixir with FLAME
Favicon
Running Elixir Phoenix on Windows
Favicon
How to use gettext in phoenix?
Favicon
Custom Instrumentation for a Phoenix App in Elixir with AppSignal
Favicon
Building a Table of Contents Component for a Phoenix Blog
Favicon
Mastering Phoenix Framework - Part 2
Favicon
Mobile app development with LiveView Native and Elixir. Part - 3
Favicon
How to integrate Tabler Icons into your Phoenix project
Favicon
Mobile app development with LiveView Native and Elixir. Part - 2
Favicon
Mobile app development with LiveView Native and Elixir
Favicon
(Unofficial) Getting Started with Elixir Phoenix Guide
Favicon
Using Ecto (without Db) for validating Phoenix form
Favicon
API Prototypes with dbb: Another step to better prototypes
Favicon
Adding stream_async() to Phoenix LiveView
Favicon
SaladUI - Implement avatar component for Phoenix LiveView
Favicon
Connectivity status with Phoenix LiveView
Favicon
Taming data with Ecto.Enum and Ecto.Type
Favicon
ecto's cast/4 function explained
Favicon
Phoenix Liveview components for Shadcn UI
Favicon
How to run a local Phoenix app on another machine

Featured ones: