How to add a field to a schema using Ecto?

I’m reading Programming Phoenix LiveView and in one chapter they create a User table using the CLI

$ mix phx.gen.auth Accounts User users

This generate the following schema

// lib/pento/accounts/user.ex
  schema "users" do
    field :email, :string
    field :password, :string, virtual: true, redact: true
    field :hashed_password, :string, redact: true
    field :confirmed_at, :naive_datetime

    timestamps()
  end

I want to add a new field to this schema and to my database. I added field :username, :string to the schema

  schema "users" do
    field :email, :string
    field :username, :string, null: false
    field :password, :string, virtual: true, redact: true
    field :hashed_password, :string, redact: true
    field :confirmed_at, :naive_datetime

    timestamps()
  end

And ran ecto migrate again

$ mix ecto.migrate
00:02:35.628 [info] Migrations already up
$ mix ecto.create
The database for Pento.Repo has already been created

But when I check my database the field isn’t there.

Whats the proper way to add fields and modify an schema?

2 Likes

I see it’s your first post. Welcome!

The book you are reading does expect you to have some knowledge of Elixir and Ecto beforehand. Stick to the main quest or learn these skills upfront a little bit, otherwise you will be fighting monsters that are out of your league.

But as you are new, a gift I will give you :slight_smile:

Answer
You also need to create a migration for the database changes (now you only updated the model). If you had not run the migrations yet, you could have added the field in the “create_user_table” migration before running them.

In this case you want to ‘alter’ an existing table by creating a new migration.

Google: `mix ecto.gen.migration alter’

https://hexdocs.pm/ecto_sql/Ecto.Migration.html

4 Likes

Aside of what’s said already I wonder if you have some misunderstanding from other languages/frameworks. ecto does not updates database after you change model (in function programming we use schema naming instead). You need to understand that schema is not a direct database representation, but a representation of final data which you receive when casting parameters or fetching entries from database.

An Ecto schema maps external data into Elixir structs.

The definition of the schema is possible through two main APIs: schema/2 and embedded_schema/1.

schema/2 is typically used to map data from a persisted source, usually a database table, into Elixir structs and vice-versa. For this reason, the first argument of schema/2 is the source (table) name. Structs defined with schema/2 also contain a __meta__ field with metadata holding the status of the struct, for example, if it has been built, loaded or deleted.

(…)

Besides working as data mappers, embedded_schema/1 and schema/2 can also be used together to decouple how the data is represented in your applications from the database. (…)

Source: Ecto.Schema

On the other side we have a migration which by default are located in priv/repo/migrations directory. Those files modify your database. You may wonder why we need a schema or why we can’t cast the parameters to the migration directly. As said schema does not represents your database directly, but helps with translating data. schema in Phoenix have few extra features like for example you may find source and virtual options:

  • :source - Defines the name that is to be used in the database for this field. This is useful when attaching to an existing database. The value should be an atom. This is a last minute translation before the query goes to the database. All references within your Elixir code must still be to the field name, such as in association foreign keys.
    (…)
  • :virtual - When true, the field is not persisted to the database. Notice virtual fields do not support :autogenerate nor :read_after_writes.

Source: Ecto.Schema.field/3

2 Likes

Create the migration that adds the username, then run mix ecto.migrate and you’ll be fine.

However, if you didn’t know this you definitely have some reading to do.

1 Like