phoenix mvc 中的函数 Routes.hello_path/3 未定义(模块路由不可用)

问题描述 投票:0回答:1

└─$ 灵药-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
model-view-controller elixir phoenix-framework phoenix-live-view
1个回答
0
投票

Phoenix 在 1.7 版本中改变了生成 URL 的方式,引入了 验证的路由来替换旧的 路由助手

之前(<1.7)

mix phx.new
将生成一个
MyAppWeb
文件,其中包含类似

的行
alias HelloWeb.Router.Helpers, as: Routes

您认为按原样使用:

Routes.hello_path(@conn, :show, messenger: 'Frank')

(1.7+)之后

mix phx.new
现在会生成一个
MyAppWeb
,其中已替换为您共享的
def verified_routes
代码段。

您现在可以使用

~p
印记声明路线:

~p"/hello/#{"Frank"}"
# or
~p"/hello/#{[messenger: "Frank"]}"

印记只是添加一些编译时验证,但在运行时它最终只会生成“/hello/Frank”字符串。

此更改不会影响更改之前使用生成器生成的现有项目。

© www.soinside.com 2019 - 2024. All rights reserved.