NOTE:
The internet is filled with programming articles written by inexperienced programmers. Same is with this article so read it with a grain of salt.
=====================================================================
If you are reading this, then chances are pretty wild that you know what enum is and why you want it. So, I wont bother wasting your time explaining them. Let's get straight to the point.
defmodule Stipe.Repo.Migrations.AlterDailyUpdate do
use Ecto.Migration
def up do
execute("CREATE TYPE daily_update_status AS ENUM('In Progress', 'In Testing', 'Done');")
execute("ALTER TABLE daily_updates ALTER COLUMN status DROP DEFAULT;")
execute("
ALTER TABLE daily_updates
ALTER COLUMN status TYPE daily_update_status
USING
CASE status
WHEN NULL then 'In Progress'
WHEN 0 then 'In Progress'
end :: daily_update_status;
")
execute("
ALTER TABLE daily_updates
ALTER COLUMN status SET DEFAULT 'In Progress';
")
end
def down do
execute("ALTER TABLE daily_updates ALTER COLUMN status DROP DEFAULT;")
execute("
ALTER TABLE daily_updates
ALTER COLUMN status TYPE INT
USING
CASE status
WHEN NULL then 0
WHEN 'In Progress' then 0
WHEN 'In Testing' then 1
WHEN 'Done' then 2
end :: integer;
")
execute("
ALTER TABLE daily_updates
ALTER COLUMN status SET DEFAULT 0;
")
execute("DROP TYPE IF EXISTS daily_update_status;")
end
end
This piece of code is a migration which alters the structure of the table DailyUpdates
. Previously, I had set status
column with integer but now I wanted to use postgres enum.
I like to define up
and down
function whenever I am using execute
because when we use execute
, migrations are not reversible.
The first line in up
function is creating an enum data type. Then it drops any default value that was set from the previous migration. The enum data type is then assigned to the status
column. If the status column has data 0 or NULL then it will be mapped. Anything else than that and the migration will fail.
The down
function is reverting the migration.
Now, that we are done with migrations, let's go to our schema.
defmodule Stipe.Standup.DailyUpdate do
use Ecto.Schema
import Ecto.Changeset
alias Stipe.Accounts.User
schema "daily_updates" do
field :remarks, :string
field :started_on, :date
field :status, :string
field :task_number, :string
field :time_spent, :decimal
belongs_to :user, User
timestamps()
end
def statuses do
["In Progress": "In Progress", "In Testing": "In Testing", Done: "Done"]
end
@doc false
def changeset(daily_update, attrs) do
daily_update
|> cast(attrs, [:task_number, :status, :time_spent, :started_on, :remarks])
|> cast_assoc(:user)
|> assoc_constraint(:user)
|> validate_required([:task_number, :time_spent, :started_on, :remarks])
end
end
Normally we define our status
field as type string. I have also defined statuses
function that returns a list of our supported statuses. We can use this function to populate the form.
To use the statuses function in template, we will alias the Stipe.Standup.DailyUpdate in the view.
defmodule StipeWeb.DailyUpdateView do
use StipeWeb, :view
alias Stipe.Standup.DailyUpdate
import Stipe.Utils.Date
end
In our template, we can call DailyUpdate.statuses
<%= form_for @changeset, @action, fn f -> %>
<%= if @changeset.action do %>
<div class="alert alert-danger">
<p>Oops, something went wrong! Please check the errors below.</p>
</div>
<% end %>
<%= label f, :task_number %>
<%= text_input f, :task_number %>
<%= error_tag f, :task_number %>
<%= label f, :status %>
<%= select f, :status, DailyUpdate.statuses %>
<%= error_tag f, :status %>
<%= label f, :time_spent %>
<%= number_input f, :time_spent, step: "any" %>
<%= error_tag f, :time_spent %>
<%= label f, :started_on %>
<%= date_input f, :started_on %>
<%= error_tag f, :started_on %>
<%= label f, :remarks %>
<%= text_input f, :remarks %>
<%= error_tag f, :remarks %>
<div>
<%= submit "Save" %>
</div>
<% end %>
It will list the supported statuses and also select the chosen status on edit.
Top comments (0)