Phoenix

elixir
Vad?
- Framework ovanpå Elixir
- Ruby on Rails på räls
- Explicit istället för implicit
- Concurrency first
- Funktionellt
├── _build
├── assets
├── config
├── deps
├── lib
│ └── cannelloni <- domain / business logic
│ └── cannelloni_web.ex <- webserver logic
├── priv
└── test
Hur ser det ut?
├── _build
├── assets
├── config
├── deps
├── lib
│ └── cannelloni <- domain / business logic
│ └── cannelloni_web.ex <- webserver logic
├── priv
└── test
Hur ser det ut?
lib/cannelloni_web
├── channels
│ └── user_socket.ex
├── controllers
│ └── page_controller.ex
├── templates
│ ├── layout
│ │ └── app.html.eex
│ └── page
│ └── index.html.eex
├── views
│ ├── error_helpers.ex
│ ├── error_view.ex
│ ├── layout_view.ex
│ └── page_view.ex
├── endpoint.ex
├── gettext.ex
├── router.ex
└── telemetry.ex
Hur ser det ut?
lib/cannelloni_web
├── channels
│
├── controllers
│
├── live
│ └── recipe_live
│
│
├── templates
│
│
├── views
│
│
│
│
├── endpoint.ex
├── gettext.ex
├── router.ex
└── telemetry.ex
defmodule CannelloniWeb.Router do
use CannelloniWeb, :router
...
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :fetch_current_user
plug :fetch_username
plug :put_root_layout, {CannelloniWeb.LayoutView, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
end
scope "/", CannelloniWeb do
pipe_through [:browser, :redirect_if_user_is_authenticated]
get "/users/register", UserRegistrationController, :new
post "/users/register", UserRegistrationController, :create
get "/users/log_in", UserSessionController, :new
post "/users/log_in", UserSessionController, :create
end
scope "/", CannelloniWeb do
pipe_through [:browser, :require_authenticated_user]
live "/recipes", RecipeLive.Index
live "/recipes/new", RecipeLive.New
end
end
defmodule CannelloniWeb.UserRegistrationController do
use CannelloniWeb, :controller
alias Cannelloni.Accounts
alias Cannelloni.Accounts.User
alias CannelloniWeb.UserAuth
def new(conn, _params) do
changeset = Accounts.change_user_registration(%User{})
render(conn, "new.html", changeset: changeset)
end
def create(conn, %{"user" => user_params}) do
case Accounts.register_user(user_params) do
{:ok, user} ->
{:ok, _} =
Accounts.deliver_user_confirmation_instructions(
user,
&Routes.user_confirmation_url(conn, :confirm, &1)
)
conn
|> put_flash(:info, "User created successfully.")
|> UserAuth.log_in_user(user)
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
end
Varför ska vi använda det?
- Alla connections får en egen process
- Skalbarhet per default
- Realtid per default
- lätt att kommunicera mellan processer
- Hit the ground running
- Elixir (och Erlang) är vettiga byggstenar
Live view
Vad?
- Ett tillägg till Phoenix för att göra vyer dynamiska
- Använder websockets
- Fortfarande i beta (v0.15.0)
Hur?
- Skickar endast små diffar till servern
- Alla klienter har en egen process, kan inte bli chokead
Varför?
- Slipper Javascript
- Vyerna är deklarativt skrivna
- Realtids-synk med backend
- Statiskt renderad "first meaningful paint" (till skillnad från JS-sidor)
- Bra för dåliga anslutningar (dåligt för offline-support)
...
<ul id="ingredient-list">
<%= for ingredient <- Enum.reverse(@recipe.ingredients) do %>
<li class="ingredient-list-item">
<%= ingredient %>
</li>
<% end %>
<%= if @current_user do %>
<li id="add-ingredient-input">
<input id="add-ingredient" type="text" phx-key="Enter" phx-window-keydown="add_ingredient" phx-hook="Input"
placeholder="T.ex. krossade tomater"/>
</li>
<% end %>
</ul>
show.html.leex
...
def mount(_params, session, socket) do
{:ok, assign(socket, :current_user, session["current_user"])}
end
def handle_params(%{"id" => id}, _, socket) do
{:noreply, assign(socket, :recipe, RecipeList.get_recipe!(id))}
end
def handle_event("add_ingredient", %{"value" => ingredient}, socket) do
{:ok, recipe} = RecipeList.add_ingredient(socket.assigns.recipe, ingredient)
socket =
socket
|> assign(:recipe, recipe)
|> push_event("clear_input", %{})
{:noreply, socket}
end
end
show.ex
Live view
Vad?
- Ett tillägg till Phoenix för att göra vyer dynamiska
- Använder websockets
- Fortfarande i beta (v0.15.0)
Hur?
- Skickar endast små diffar till servern
- Alla klienter har en egen process, kan inte bli chokead
Varför?
- Slipper Javascript
- Vyerna är deklarativt skrivna
- Realtids-synk med backend
- Statiskt renderad "first meaningful paint" (till skillnad från JS-sidor)
- Bra för dåliga anslutningar (dåligt för offline-support)
Channels (PubSub)
- Realtidskommunicering mellan processer
- Fungerar mellan olika noder i ett kluster
Presence
-
Live Telemetrics
Testing
- Inbyggda testing moduler
- Väldigt snabbt (krävs ingen browser)
- Kan dock inte testa javascript
Tack
deck
By Mikael Gråborg
deck
- 114