Now a days writing phoenix CRUD application is not a hurdle for beginners. After completing installation with in few steps your initial project is up and running. and we have some magic codes to create new HTML resources with views,controllers and contexts. now we are not going to that part right now, before using those magic codes in your project having a clear picture about context, controllers and views will give a happy path in your coding life. so let us jump to a all those things by a sample phoenix project.
The parts of a html resource in phoenix project is as follows
- Migration
- Schema
- Changeset
- Context
- Controller
- View
- Template
- Router
Let's do a project by covering all these steps
Create a phoenix project
mix phx.new greeting_cards
We are almost there! The following steps are missing:
$ cd greeting_card
Then configure your database in config/dev.exs and run:
$ mix ecto.create
Start your Phoenix app with:
$ mix phx.server
You can also run your app inside IEx (Interactive Elixir) as:
$ iex -S mix phx.server
Hope you done all step by step, in case of any errors check installation guide
Let's start with a feature
We created a project named greeting_cards my let us assume its an app for greeting card design collections as an initial step we should feed collection of greeting cards in our database.
Migration
mix ecto.gen.migration create_greeting_cards
==> greeting_card
Compiling 14 files (.ex)
Generated greeting_card app
* creating priv/repo/migrations/20220903182959_create_greeting_cards.exs
Navigate to .exs generated shown in output
Update the file with these scripts to
defmodule GreetingCard.Repo.Migrations.CreateGreetingCards do
use Ecto.Migration
def change do
create table(:greeting_cards) do
add :name, :string
add :type, :string
add :template, :string
add :print_quality, :string
add :preview, :string
end
end
end
And run mix ecto.migrate
Will create table "greeting_cards" in your database
Context
An encapsulation layer for data access and validation, so the schemas are grouped under a context name for more details
refer Contexts
Create
lib/greeting_cards/feeder.ex
lib/greeting_cards/feeder/ #Directory
Schema
An Ecto.Schema maps External data into elixir structs, a Schema file contains specification of fields for database table and Changesets to allow filtering, casting, validation and definition of constraints when manipulating structs.
Schema
Chngeset
Here to create our schema for greeting cards
Create
lib/greeting_cards/feeder/greeting_card.ex
defmodule GreetingCard.Feeder.GreetingCard do
use Ecto.Schema
import Ecto.Changeset
schema "greeting_cards" do
field :name, :string
field :type, :string
field :template, :string
field :print_quality, :string
field :preview, :string
end
def changeset(greeting_card, params \\ %{}) do
greeting_card
|> cast(params, [:name, :type, :template, :print_quality, :preview])
|> validate_required([:name, :type, :print_quality])
end
Write Context functions
We mapped our database table with an Elixir struct by a Schema module then we can write functions to do CRUD operations
To write CRUD functions Refer
Ecto.Repo
Update lib/greeting_cards/feeder.ex
defmodule GreetingCard.Feeder do
alias GreetingCard.Repo
alias GreetingCard.Feeder.GreetingCard
def list_greeting_cards do
Repo.all(GreetingCard)
end
def create_greeting_card(params) do
%GreetingCard{}
|> GreetingCard.changeset(params)
|> Repo.insert()
end
def show_greeting_card(id) when not is_nil(id) do
Repo.get(GreetingCard, id)
end
def update_greeting_card(greeting_card, params) do
greeting_card
|> GreetingCard.changeset(params)
|> Repo.update()
end
def delete_greeting_card(greeting_card) do
Repo.delete(greeting_card)
end
end
Run and test our code using iex shell
So far we are writing codes to create a feature, debugging and running is an another interested part of coding, before running our feature in to a web server let's run that in our iex shell and make sure all our functions are working as we expected
In terminal project root directory run
iex -S mix
Call your functions in shell through module name here
iex(2)> GreetingCard.Feeder.create_greeting_card(%{name: "card1",type: "birthday", template: "template1",print_quality: "canva"})
[debug] QUERY OK db=1.4ms queue=2.0ms idle=1173.7ms
INSERT INTO "greeting_cards" ("name","print_quality","template","type") VALUES ($1,$2,$3,$4) RETURNING "id" ["card1", "canva", "template1", "birthday"]
↳ :erl_eval.do_apply/6, at: erl_eval.erl:685
{:ok,
%GreetingCard.Feeder.GreetingCard{
__meta__: #Ecto.Schema.Metadata<:loaded, "greeting_cards">,
id: 1,
name: "card1",
preview: nil,
print_quality: "canva",
template: "template1",
type: "birthday"
}}
iex(3)> GreetingCard.Feeder.list_greeting_cards [debug] QUERY OK source="greeting_cards" db=0.9ms idle=1687.7ms
SELECT g0."id", g0."name", g0."type", g0."template", g0."print_quality", g0."preview" FROM "greeting_cards" AS g0 []
↳ :erl_eval.do_apply/6, at: erl_eval.erl:685
[
%GreetingCard.Feeder.GreetingCard{
__meta__: #Ecto.Schema.Metadata<:loaded, "greeting_cards">,
id: 1,
name: "card1",
preview: nil,
print_quality: "canva",
template: "template1",
type: "birthday"
}
]
iex(4)> GreetingCard.Feeder.show_greeting_card(1)
[debug] QUERY OK source="greeting_cards" db=0.5ms queue=0.6ms idle=373.3ms
SELECT g0."id", g0."name", g0."type", g0."template", g0."print_quality", g0."preview" FROM "greeting_cards" AS g0 WHERE (g0."id" = $1) [1]
↳ :erl_eval.do_apply/6, at: erl_eval.erl:685
%GreetingCard.Feeder.GreetingCard{
__meta__: #Ecto.Schema.Metadata<:loaded, "greeting_cards">,
id: 1,
name: "card1",
preview: nil,
print_quality: "canva",
template: "template1",
type: "birthday"
}
Run with server
So far we are working on the data layer of our feature, we have to implement view and controller layers as well. Phoenix project contains a Routing Module by default to specify routers. They are the main hubs of phoenix application, They match HTTP requests to controller actions,wire up real-time channel handlers, etc..
Refer Request Life cycle
Top comments (0)