🦆Data persistence
Depending on time, this chapter may not have been covered during the recording/live talk. Fret not, we have documented the process of setting up data persistence with Phoenix in this chapter.
If you want to checkout data persistence in action, go to the complete
branch by doing git switch complete
.
The core essentials for data persistence with SQLite3 should have already been setup for you when you first initialized the project. Phoenix uses the widely popular Ecto database library that helps abstract the process of database connection and querying on your behalf.
Creating a schema and migration
Phoenix comes with various handy Mix tasks to help with this task. Use the following command to generate the necessary database schema and migration file for the to-do table:
The command above will automatically generate a file under lib/practical_elixir_demo/
called todo.ex
along with a database migration file under priv/repo/migrations
.
If you open todo.ex
, you will see the following:
To quickly run through what you've done so far:
mix phx.gen.schema
: creates a database schema and corresponding migration fileContains fields
title
,description
, andis_done
Has auto-generated UUID from
--binary-id
Table name is
todo
Elixir module name is
Todo
The schema module contains:
schema
declaration for the same fields we declared duringmix phx.gen.schema
changeset/2
function that provides model validation
Running database migrations
Before running the migration for the new todo
table, let us first delete the existing Todo
and TodoItem
modules (by deleting the files). These are all redundant modules. You may notice some compile errors as there were some references to the get_items/0
function in Todo
. You may add a dummy function to the new Todo
module we have made:
Finally, move the todo.ex
file created into the todo/
folder.
Now, you can run the migration via:
Then, make sure you restart the local development server.
You may also need to make the following changes to the HEEx and functional component to work with the latest changes:
Note the use of is_done
instead of is_done?
Since todo_list
should now contain the database schema objects that already have a built-in id
field (random UUID), we can use that as the id
instead of the relative position.
If you refresh your page, you should see that there are no to-do items in the to-do list. This is perfectly normal as your database table is still empty.
Retrieving all to-do items
Let's first populate the behavior of the dummy get_items/0
function we made earlier. We can use the PracticalElixirDemo.Repo
module to provide some helper functions to easily do that:
Repo.all(__MODULE__)
is the same as Repo.all(PracticalElixirDemo.Todo)
and all it does is perform a SELECT * FROM todo;
for us and map the results into PracticalElixirDemo.Todo
structs that we can use in the front-end.
Creating to-do items
Then, to create a new to-do item, we can continue using the helper functions from Repo
and use the Repo.insert/2
function:
Similar to Repo.all/1
, Repo.insert/2
performs an INSERT INTO todo VALUES (...)
query on your behalf.
We can replace the add-todo
event in our LiveView controller with a call to this create_todo/2
function:
Marking items as done/not done
The final piece of behavior we are migrating is the mark as done/not done functionality. In this case, we will collapse the behavior into a single mark-todo
event that both the buttons will use (be sure to update the functional component's phx-click
binding):
This way, we leave the toggling behavior to the Todo
model:
We first retrieve the matching to-do based on the given id
, and then, we toggle the is_done
field using Ecto.Changeset.change/2
function and then perform the update using Repo.update!/1
.
The !
that follow one
and update
are to indicate functions that raise an exception when an entry is not found or cannot be updated respectively. They have counterparts that return an :error
state instead, but we have opted to avoid using them this time.
If you restart your application now, you can play around with the to-do list and you will notice that the to-do items are persisted even after refreshing the page.
This also concludes this guide on practical functional programming with Elixir and Phoenix! As mentioned earlier, the complete code for the application built for this guide is found on the complete
branch of this repository. If you are interested in learning more about web development with Phoenix, please refer to the Resources for the recommended readings/resources to follow!
All the best in your Elixir journey! :D
Last updated