From jutsu-phoenix
Implements Phoenix controllers to handle HTTP requests, covering actions, parameter extraction, rendering templates, flash messages, and redirects. Useful for Elixir/Phoenix web development.
How this skill is triggered — by the user, by Claude, or both
Slash command
/jutsu-phoenix:phoenix-controllersThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Phoenix controllers are the intermediary modules between the router and views in a Phoenix application. They handle HTTP requests, process parameters, interact with contexts, and determine what response to send back to the client. Controllers are stateless and receive a connection struct (`conn`) that represents the current HTTP request.
Phoenix controllers are the intermediary modules between the router and views in a Phoenix application. They handle HTTP requests, process parameters, interact with contexts, and determine what response to send back to the client. Controllers are stateless and receive a connection struct (conn) that represents the current HTTP request.
The simplest Phoenix controller uses the HelloWeb, :controller macro and defines actions as functions that receive the connection and parameters:
defmodule HelloWeb.PageController do
use HelloWeb, :controller
def home(conn, _params) do
render(conn, :home, layout: false)
end
end
Each controller action receives:
conn - The Plug.Conn struct representing the HTTP request/responseparams - A map containing request parameters from the URL, query string, and request bodyUse pattern matching to extract specific parameters from the params map:
defmodule HelloWeb.HelloController do
use HelloWeb, :controller
def show(conn, %{"messenger" => messenger}) do
render(conn, :show, messenger: messenger)
end
end
To access both a specific parameter and the full params map, use pattern matching with the = operator:
def show(conn, %{"messenger" => messenger} = params) do
# Access to both messenger and the full params map
render(conn, :show, messenger: messenger)
end
When an action doesn't need parameters, prefix the variable with an underscore to avoid compiler warnings:
def index(conn, _params) do
render(conn, :home)
end
Action names can be customized independently of the template name:
defmodule HelloWeb.PageController do
use HelloWeb, :controller
def index(conn, _params) do
# Renders :home template but action is named :index
render(conn, :home)
end
end
Update the router accordingly:
get "/", PageController, :index
Use the render/3 function to render HTML templates via Phoenix Views:
defmodule HelloWeb.HelloController do
use HelloWeb, :controller
def show(conn, %{"messenger" => messenger}) do
render(conn, :show, messenger: messenger)
end
end
The controller and view must share a root name (e.g., HelloController and HelloHTML).
Disable the layout for specific actions:
def home(conn, _params) do
render(conn, :home, layout: false)
end
Pass data to templates using assign/3:
def show(conn, %{"messenger" => messenger}) do
conn
|> assign(:messenger, messenger)
|> render(:show)
end
Chain multiple assigns for cleaner code:
def show(conn, %{"messenger" => messenger}) do
conn
|> assign(:messenger, messenger)
|> assign(:receiver, "Dweezil")
|> render(:show)
end
For concise syntax, pass assigns directly to render/3:
def show(conn, %{"messenger" => messenger}) do
render(conn, :show, messenger: messenger, receiver: "Dweezil")
end
Configure supported response formats in your controller configuration:
def controller do
quote do
use Phoenix.Controller,
formats: [:html, :json]
...
end
end
This allows controllers to respond with different formats based on the request.
Use put_flash/3 to set temporary messages:
defmodule HelloWeb.PageController do
use HelloWeb, :controller
def home(conn, _params) do
conn
|> put_flash(:error, "Let's pretend we have an error.")
|> render(:home, layout: false)
end
end
Flash message types:
:info - Informational messages:error - Error messages:warning - Warning messages (custom):success - Success messages (custom)Remove all flash messages from the connection:
clear_flash(conn)
Combine flash messages with redirects to provide context after navigation:
def home(conn, _params) do
conn
|> put_flash(:error, "Let's pretend we have an error.")
|> redirect(to: ~p"/redirect_test")
end
Redirect to another route using the verified routes syntax:
def create(conn, params) do
# ... create logic
redirect(conn, to: ~p"/posts")
end
Include dynamic parameters in redirects:
def create(conn, params) do
# ... create post
redirect(conn, to: ~p"/posts/#{post}")
end
Redirect to external URLs:
def external(conn, _params) do
redirect(conn, external: "https://example.com")
end
Action fallback controllers handle error cases elegantly by centralizing error handling logic:
defmodule HelloWeb.MyController do
use Phoenix.Controller
action_fallback HelloWeb.MyFallbackController
def show(conn, %{"id" => id}, current_user) do
with {:ok, post} <- fetch_post(id),
:ok <- authorize_user(current_user, :view, post) do
render(conn, :show, post: post)
end
end
end
The fallback controller handles non-ok tuples:
defmodule HelloWeb.MyFallbackController do
use Phoenix.Controller
def call(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)
|> put_view(HelloWeb.ErrorHTML)
|> render(:"404")
end
def call(conn, {:error, :unauthorized}) do
conn
|> put_status(403)
|> put_view(HelloWeb.ErrorHTML)
|> render(:"403")
end
end
Test controller actions using ConnCase:
defmodule HelloWeb.PostControllerTest do
use HelloWeb.ConnCase
import Hello.BlogFixtures
@create_attrs %{body: "some body", title: "some title"}
@update_attrs %{body: "some updated body", title: "some updated title"}
@invalid_attrs %{body: nil, title: nil}
describe "index" do
test "lists all posts", %{conn: conn} do
conn = get(conn, ~p"/posts")
assert html_response(conn, 200) =~ "Listing Posts"
end
end
describe "show" do
test "displays a single post", %{conn: conn} do
post = post_fixture()
conn = get(conn, ~p"/posts/#{post}")
assert html_response(conn, 200) =~ post.title
end
end
end
Assert redirects in tests:
test "redirects after create", %{conn: conn} do
conn = post(conn, ~p"/posts", post: @create_attrs)
assert %{id: id} = redirected_params(conn)
assert redirected_to(conn) == ~p"/posts/#{id}"
end
Verify flash messages are set correctly:
test "sets flash message on error", %{conn: conn} do
conn = post(conn, ~p"/posts", post: @invalid_attrs)
assert get_flash(conn, :error) == "Could not create post"
end
Use this skill when you need to:
~p sigil for route paths to catch errors at compile time~p)npx claudepluginhub thedotmack/han --plugin jutsu-phoenixImplements Phoenix controllers to handle HTTP requests, covering actions, parameter extraction, rendering templates, flash messages, and redirects. Useful for Elixir/Phoenix web development.
Guides Phoenix web application development including LiveView, contexts, channels, and runtime configuration best practices.
Guides Phoenix web app development in Elixir: LiveView lifecycle and components, context design and generation, channels, routers, plugs, project structure, and troubleshooting.