Skip to content

Phoenix Model Layer

The model layer is mostly used to get data from the database and interact with it.

Migration files

We can create migration files to tell phoenix to change the database. We can use a command to generate it:

mix ecto.gen.migration add_topics

The migration file will be stored in priv/repo/migrations directory.

The migration file will contain a set of instructions for phoenix on how to change the database.

So, if we want to create a table topics with a column title of type string we can use the following code:

defmodule Discuss.Repo.Migrations.AddTopics do
  use Ecto.Migration

  def change do

    create table(:topics) do
      add :title, :string
    end

  end
end

Example on alter / reference

def change do

    alter table(:topics) do
        add :user_id, references(:users)
    end

end

The migration process can be executed by running a command:

mix ecto.migrate

Model files

The models are located into web/models directory.

We can create a new Topic model by creating a web/models/topic.ex file with following content.

defmodule Discuss.Topic do
  use Discuss.Web, :model

  schema "topics" do
    field :title, :string
  end

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:title])
    |> validate_required([:title])
  end

end

The line use Discuss.Web, :model is used to imports the model method from web/web.ex which defines all the behaviours that controller have.

Works is similar to class inheritance in OOP - extending the BaseModel class.


The schema part describes which table and columns to use.


The changeset function computes a changed model. It accepts the struct (current model) and the hash with all the properties to update.

  • It casts it - produces the changeset,
  • validates it - adds errors to the changeset if there are any
  • Returns the changeset

We can produce the changeset by doing following

iex(3)> struct = %Discuss.Topic{}
%Discuss.Topic{
  __meta__: #Ecto.Schema.Metadata<:built, "topics">,
  id: nil,
  title: nil
}
iex(4)> params = %{title: "A new Topic"}
%{title: "A new Topic"}
iex(5)> Discuss.Topic.changeset(struct, params)
#Ecto.Changeset<
  action: nil,
  changes: %{title: "A new Topic"},
  errors: [],
  data: #Discuss.Topic<>,
  valid?: true
>