Phoenix 1.3
Design with intent
Biggest and the best change?
The Generator
Phoenix -> phx
1.2 | 1.3 | Alias |
---|---|---|
iex -S mix phoenix.server | iex -S mix phx.server | ips |
mix phoenix.routes | mix phx.routes | mpr |
mix phoenix.gen.json | mix phx.gen.json | mpgj |
mix phoenix.gen.channel | mix phx.gen.channel | mpgc |
Alias FTW
1.2
1.3
Project structure change
├── README.md
├── _build
├── config
├── deps
├── lib
│ ├── granpals
│ └── granpals.ex
├── mix.exs
├── mix.lock
├── priv
├── test
│ ├── channels
│ ├── controllers
│ ├── models
│ ├── support
│ ├── test_helper.exs
│ └── views
└── web
├── channels
├── controllers
├── gettext.ex
├── models
├── router.ex
├── templates
├── views
└── web.ex
├── README.md
├── _build
├── config
├── deps
├── lib
│ ├── granpals
│ ├── granpals.ex
│ ├── granpals_web
│ └── granpals_web.ex
├── mix.exs
├── mix.lock
├── priv
└── test
├── granpals
├── granpals_web
├── support
└── test_helper.exs
Phoenix 1.3 Lib folder
├── granpals
│ ├── accounts
│ │ ├── accounts.ex
│ │ ├── credential.ex
│ │ └── user.ex
│ ├── application.ex
│ ├── jobs
│ │ ├── job.ex
│ │ └── jobs.ex
│ └── repo.ex
├── granpals.ex
├── granpals_web
│ ├── channels
│ │ └── user_socket.ex
│ ├── controllers
│ │ ├── fallback_controller.ex
│ │ ├── job_controller.ex
│ │ ├── page_controller.ex
│ │ ├── session_controller.ex
│ │ └── user_controller.ex
│ ├── endpoint.ex
│ ├── gettext.ex
│ ├── guardian_serializer.ex
│ ├── router.ex
│ ├── templates
│ │ ├── layout
│ │ │ └── app.html.eex
│ │ └── page
│ │ └── index.html.eex
│ └── views
│ ├── changeset_view.ex
│ ├── error_helpers.ex
│ ├── error_view.ex
│ ├── job_view.ex
│ ├── layout_view.ex
│ ├── page_view.ex
│ ├── session_view.ex
│ └── user_view.ex
└── granpals_web.ex
Context
For example, any time you call Elixir’s standard library, be it Logger.info/1 or Stream.map/2, you are accessing different contexts.
Internally, Elixir’s logger is made of multiple modules, such as Logger.Config and Logger.Backends, but we never interact with those modules directly.
Contexts are dedicated modules that expose and group related functionality.
When building a Phoenix project, we are first and foremost building an Elixir application.
Phoenix’s job is to provide a web interface into our Elixir application.
Context
Phoenix 1.2 Example
defmodule Granpals.UserController do
use Granpals.Web, :controller
alias Granpals.User
def index(conn, _params) do
users = Repo.all(User)
render(conn, "index.json", users: users)
end
def create(conn, %{"user" => user_params}) do
changeset = %User{}
|> User.changeset(user_params)
case Repo.insert(changeset) do
{:ok, user} ->
conn
|> put_status(:created)
|> render("show.json", user: user)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(Granpals.ChangesetView, "error.json", changeset: changeset)
end
end
end
Phoenix 1.3 Example
defmodule GranpalsWeb.UserController do
use GranpalsWeb, :controller
alias Granpals.Accounts
alias Granpals.Accounts.User
action_fallback GranpalsWeb.FallbackController
def index(conn, _params) do
users = Accounts.list_users()
render(conn, "index.json", users: users)
end
def create(conn, %{"user" => user_params}) do
with {:ok, %User{} = user} <- Accounts.create_user(user_params) do
conn
|> put_status(:created)
|> render("show.json", user: user)
end
end
end
Phoenix 1.3 Example
defmodule GranpalsWeb.UserController do
use GranpalsWeb, :controller
alias Granpals.Accounts
alias Granpals.Accounts.User
action_fallback GranpalsWeb.FallbackController
def add_social_credential(conn, %{"social_credential" => social_params}) do
user = Accounts.get_user! social_params["user_id"]
with {:ok, %User{} = user} <- Accounts.add_social_credential_to_user(social_params) do
conn
|> put_status(:created)
|> render("show.json", user: user)
end
end
end
Phoenix 1.3 Example
defmodule GranpalsWeb.UserController do
use GranpalsWeb, :controller
alias Granpals.Accounts
alias Granpals.Accounts.User
action_fallback GranpalsWeb.FallbackController
def create_user_with_social_credential(conn, %{"social_credential" => social_params}) do
with {:ok, %User{} = user} <- Accounts.create_user_with_social(social_params) do
conn
|> put_status(:created)
|> render("show.json", user: user)
end
end
end
Phoenix 1.3 Example
defmodule Granpals.Accounts do
import Ecto.Query, warn: false
alias Granpals.Repo
alias Granpals.Accounts.{User, Credential}
def list_users do
Repo.all(User)
end
def get_user!(id), do: Repo.get!(User, id)
def create_user(attrs \\ %{}) do
%User{}
|> User.changeset(attrs)
|> Ecto.Changeset.cast_assoc(:credential, with: &Credential.changeset/2)
|> Repo.insert()
end
def add_social_credential_to_user(%User{} = user, attrs) do
user
|> User.changeset
|> Ecto.Changeset.cast_assoc(:credential, with: &Credential.social_changeset/2)
|> Repo.insert()
end
def create_user_with_social_credential(attrs \\ %{}) do
create_user(attrs)
|> add_social_credential_to_user()
end
end
Phoenix 1.3 Example
defmodule Granpals.Notifications do
def send_email(to, subject, body)
def send_push(to, body)
def send_sms(to, body)
def send_all(to, subject, body)
end
Phoenix 1.3 Example
├── granpals
│ ├── accounts
│ │ ├── accounts.ex
│ │ ├── credential.ex
│ │ └── user.ex
│ ├── application.ex
│ ├── jobs
│ │ ├── job.ex
│ │ └── jobs.ex
| ├── notifications
│ │ └── notifications.ex
│ └── repo.ex
The Future
The Future
The Future
Thank you
Phoenix 1.3
By Tianyi Wang
Phoenix 1.3
- 1,086