└─$ 灵药-v
Erlang/OTP 27 [erts-15.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns]
Elixir 1.17.0 (compiled with Erlang/OTP 25)
项目结构如下 -
lib/
hello/
hello-web/
components/
controllers/
hello_html/
index.html.heex
show.html.heex
page_html/
hello_controller.ex
hello_html.ex
page_controller.ex
page_html.ex
endpoint.ex
gettext.ex
router.ex
telemetry.ex
mix.exs 正在关注 -
defmodule Hello.MixProject do
use Mix.Project
def project do
[
app: :hello,
version: "0.1.0",
elixir: "~> 1.17",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps()
]
end
router.ex 正在关注 -
defmodule HelloWeb.Router do
use HelloWeb, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, html: {HelloWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", HelloWeb do
pipe_through :browser
get "/", PageController, :home
get "/hello", HelloController, :index
get "/hello/:messenger", HelloController, :show
# resources "/users", UserController
end
# Enable LiveDashboard and Swoosh mailbox preview in development
if Application.compile_env(:hello, :dev_routes) do
import Phoenix.LiveDashboard.Router
scope "/dev" do
pipe_through :browser
live_dashboard "/dashboard", metrics: HelloWeb.Telemetry
forward "/mailbox", Plug.Swoosh.MailboxPreview
end
end
end
hello_controller.ex 正在关注 -
defmodule HelloWeb.HelloController do
use HelloWeb, :controller
def index(conn, _params) do
conn
|> put_flash(:info, "Welcome back!")
|> render("index.html")
end
def show(conn, %{"messenger" => messenger}) do
render(conn, "show.html.heex", messenger: messenger)
end
end
hello_html.ex 正在关注 -
defmodule HelloWeb.HelloHTML do
use HelloWeb, :html
embed_templates "hello_html/*"
end
index.html.heex 正在关注 -
<div class="jumbotron">
<h2>Hello World from Phoenix!2</h2>
<p>
<a href={Routes.hello_path(@conn, :show, messenger: 'Frank')} class="text-orange-700">
Say hello to Frank
</a>
</p>
</div>
show.html.heex 正在关注 -
<div class="jumbotron">
<p>
<a href="/hello" class="text-orange-700">
Go back
</a>
</p>
<h2>Hello <%= @messenger %></h2>
</div>
现在,index.html.heex 中出现问题 -
GET /hello 时出现 UndefinedFunctionError
函数 Routes.hello_path/3 未定义(模块 Routes 不可用)
它抱怨“Routes.hello_path is undefined”。
我对phoenix很陌生,在这里卡了5个小时,尝试手动理解,检查控制器,`router.ex`中的路由器定义,甚至尝试了Gemini LLM,没有运气!
与 `ReactJS`、`NextJS` 或 `Django` 相比,Phoenix 框架看起来并没有那么容易,也没有那么稳定,而且非常难学。
添加 hello_web.ex 模块 -
defmodule HelloWeb do
@moduledoc """
The entrypoint for defining your web interface, such
as controllers, components, channels, and so on.
This can be used in your application as:
use HelloWeb, :controller
use HelloWeb, :html
The definitions below will be executed for every controller,
component, etc, so keep them short and clean, focused
on imports, uses and aliases.
Do NOT define functions inside the quoted expressions
below. Instead, define additional modules and import
those modules here.
"""
def static_paths, do: ~w(assets fonts images favicon.ico robots.txt)
def router do
quote do
use Phoenix.Router, helpers: false
# Import common connection and controller functions to use in pipelines
import Plug.Conn
import Phoenix.Controller
import Phoenix.LiveView.Router
end
end
def channel do
quote do
use Phoenix.Channel
end
end
def controller do
quote do
use Phoenix.Controller,
formats: [:html, :json],
layouts: [html: HelloWeb.Layouts]
import Plug.Conn
import HelloWeb.Gettext
unquote(verified_routes())
end
end
def live_view do
quote do
use Phoenix.LiveView,
layout: {HelloWeb.Layouts, :app}
unquote(html_helpers())
end
end
def live_component do
quote do
use Phoenix.LiveComponent
unquote(html_helpers())
end
end
def html do
quote do
use Phoenix.Component
# Import convenience functions from controllers
import Phoenix.Controller,
only: [get_csrf_token: 0, view_module: 1, view_template: 1]
# Include general helpers for rendering HTML
unquote(html_helpers())
end
end
defp html_helpers do
quote do
# HTML escaping functionality
import Phoenix.HTML
# Core UI components and translation
import HelloWeb.CoreComponents
import HelloWeb.Gettext
# Shortcut for generating JS commands
alias Phoenix.LiveView.JS
# Routes generation with the ~p sigil
unquote(verified_routes())
end
end
def verified_routes do
quote do
use Phoenix.VerifiedRoutes,
endpoint: HelloWeb.Endpoint,
router: HelloWeb.Router,
statics: HelloWeb.static_paths()
end
end
@doc """
When used, dispatch to the appropriate controller/live_view/etc.
"""
defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
end
Phoenix 在 1.7 版本中改变了生成 URL 的方式,引入了 验证的路由来替换旧的 路由助手。
mix phx.new
将生成一个 MyAppWeb
文件,其中包含类似 的行
alias HelloWeb.Router.Helpers, as: Routes
您认为按原样使用:
Routes.hello_path(@conn, :show, messenger: 'Frank')
mix phx.new
现在会生成一个 MyAppWeb
,其中已替换为您共享的 def verified_routes
代码段。
您现在可以使用
~p
印记声明路线:
~p"/hello/#{"Frank"}"
# or
~p"/hello/#{[messenger: "Frank"]}"
印记只是添加一些编译时验证,但在运行时它最终只会生成“/hello/Frank”字符串。
此更改不会影响更改之前使用生成器生成的现有项目。