Repository: phoenixframework/phoenix
Pull request #5092 (2022-11-08 22:37:25)

Update import documentation in generated ErrorHTMLTest
In the process of upgrading a Phoenix 1.6.15 application to 1.7.0-rc.0 I found this typo.

adkron: We are working on other updates to the documentation and will update the PR.
djgoku: All the changes we wanted are now present. This is now ready for review.

Patch:
diff --git a/guides/howto/custom_error_pages.md b/guides/howto/custom_error_pages.md
index dcde8a6f2..385e76fa6 100644
--- a/guides/howto/custom_error_pages.md
+++ b/guides/howto/custom_error_pages.md
@@ -27,7 +27,7 @@ defmodule HelloWeb.ErrorHTML do
   end
 end
 
-defmodule HelloWeb.ErrorJSOn do
+defmodule HelloWeb.ErrorJSON do
   # If you want to customize a particular status code,
   # you may add your own clauses, such as:
   #
@@ -167,9 +167,9 @@ However, implementing the `Plug.Exception` protocol by hand can be convenient in
 
 ## Actionable errors
 
-Exception actions are functions that can be triggered by the error page, and they're basically a list of maps defining a `label` and a `handler` to be executed.
+Exception actions are functions that can be triggered from the error page, and they're basically a list of maps defining a `label` and a `handler` to be executed. As an example, Phoenix will display an error if you have pending migrations and will provide a button on the error page to perform the pending migrations.
 
-They are rendered in the error page as a collection of buttons and follow the format of:
+When `debug_errors` is `true`, they are rendered in the error page as a collection of buttons and follow the format of:
 
 ```elixir
 [
diff --git a/guides/request_lifecycle.md b/guides/request_lifecycle.md
index 925d63115..e6ac00459 100644
--- a/guides/request_lifecycle.md
+++ b/guides/request_lifecycle.md
@@ -117,7 +117,11 @@ defmodule HelloWeb.HelloHTML do
 end
 ```
 
-Now in order to add templates to this view, we can either define them as function components directly in the module:
+To add templates to this view, we can define them as function components in the module or in separate files. Function components are great for smaller templates and separate files are a good choice when you have a lot of markup or your functions start to feel unmanageable.
+
+Template files are compiled into the module as function components themselves, there is no runtime or performance difference between the two styles.
+
+Here's how you would define a template a function component:
 
 ```elixir
 defmodule HelloWeb.HelloHTML do
@@ -131,9 +135,9 @@ defmodule HelloWeb.HelloHTML do
 end
 ```
 
-You can read more about function components and the `~H` heex templates in the `Phoenix.Component` documentation. For larger templates with a lot of markup, we often want to define them in their own file. We can do that now.
+You can read more about function components and `~H` heex templates in the `Phoenix.Component` documentation.
 
-Let's delete our `def index(assigns)` function and replace it with an `embed_templates` declaration:
+Now lets define a template in its own file. First delete our `def index(assigns)` function from above and replace it with an `embed_templates` declaration:
 
 ```elixir
 defmodule HelloWeb.HelloHTML do
@@ -143,7 +147,11 @@ defmodule HelloWeb.HelloHTML do
 end
 ```
 
- Here we are telling `Phoenix.Component` to embed all `.heex` templates found in the sibling `hello` directory into our module as function definitions. Next, we need to add files to the `lib/hello_web/controllers/hello_html` directory. Note the controller name (`HelloController`), the view name (`HelloHTML`), and the template directory (`hello_html`) all follow the same naming convention and are named after each other. They are also collocated together in the directory tree:
+ Here we are telling `Phoenix.Component` to embed all `.heex` templates found in the sibling `hello_html` directory into our module as function definitions.
+
+ Next, we need to add files to the `lib/hello_web/controllers/hello_html` directory.
+
+ Note the controller name (`HelloController`), the view name (`HelloHTML`), and the template directory (`hello_html`) all follow the same naming convention and are named after each other. They are also collocated together in the directory tree:
 
 ```
 lib/hello_web
@@ -265,6 +273,8 @@ For the last piece of this puzzle, we'll need a new template. Since it is for th
 
 To do that, we'll use the special EEx tags for executing Elixir expressions: `<%=  %>`. Notice that the initial tag has an equals sign like this: `<%=` . That means that any Elixir code that goes between those tags will be executed, and the resulting value will replace the tag in the HTML output. If the equals sign were missing, the code would still be executed, but the value would not appear on the page.
 
+Remember our templates are written in HEEx (HTML+EEx). HEEx is a superset of EEx which is why it shares the `<%= %>` syntax.
+
 And this is what the template should look like:
 
 ```heex
@@ -273,7 +283,9 @@ And this is what the template should look like:
 </section>
 ```
 
-Our messenger appears as `@messenger`. We call "assigns" the values passed from the controller to views. It is a special bit of metaprogrammed syntax which stands in for `assigns.messenger`. The result is much nicer on the eyes and much easier to work with in a template.
+Our messenger appears as `@messenger`.
+
+The values we passed to the view from the controller are collectively called our "assigns". We could access our messenger value via `assigns.messenger` but through some metaprogramming, Phoenix gives us the much cleaner `@` syntax for use in templates.
 
 We're done. If you point your browser to [http://localhost:4000/hello/Frank](http://localhost:4000/hello/Frank), you should see a page that looks like this:
 
diff --git a/installer/templates/phx_single/config/dev.exs b/installer/templates/phx_single/config/dev.exs
index 9458de6b7..2e610184d 100644
--- a/installer/templates/phx_single/config/dev.exs
+++ b/installer/templates/phx_single/config/dev.exs
@@ -48,8 +48,7 @@ config :<%= @app_name %>, <%= @endpoint_module %>,
     patterns: [
       ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",<%= if @gettext do %>
       ~r"priv/gettext/.*(po)$",<% end %>
-      ~r"lib/<%= @lib_web_name %>/(live|views)/.*(ex)$",
-      ~r"lib/<%= @lib_web_name %>/templates/.*(eex)$"
+      ~r"lib/<%= @lib_web_name %>/(controllers|live|components)/.*(ex|heex)$"
     ]
   ]<% end %>
 
diff --git a/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs b/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
index 003eb461b..9757b1eba 100644
--- a/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
+++ b/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
@@ -46,8 +46,7 @@ config :<%= @web_app_name %>, <%= @endpoint_module %>,
     patterns: [
       ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",<%= if @gettext do %>
       ~r"priv/gettext/.*(po)$",<% end %>
-      ~r"lib/<%= @web_app_name %>/(live|views)/.*(ex)$",
-      ~r"lib/<%= @web_app_name %>/templates/.*(eex)$"
+      ~r"lib/<%= @web_app_name %>/(controllers|live|components)/.*(ex|heex)$"
     ]
   ]<% end %>
 
diff --git a/lib/phoenix/verified_routes.ex b/lib/phoenix/verified_routes.ex
index 7eeed8a5f..794a89f4a 100644
--- a/lib/phoenix/verified_routes.ex
+++ b/lib/phoenix/verified_routes.ex
@@ -535,6 +535,14 @@ defmodule Phoenix.VerifiedRoutes do
     |> URI.encode(&URI.char_unreserved?/1)
   end
 
+  # Segments must always start with /
+  defp verify_segment(["/" <> _ | _] = segments, route), do: verify_segment(segments, route, [])
+
+  defp verify_segment(_, route) do
+    raise ArgumentError, "paths must begin with /, got: #{Macro.to_string(route)}"
+  end
+
+  # separator followed by dynamic
   defp verify_segment(["/" | rest], route, acc), do: verify_segment(rest, route, ["/" | acc])
 
   # we've found a static segment, return to caller with rewritten query if found
@@ -561,7 +569,7 @@ defmodule Phoenix.VerifiedRoutes do
 
   defp verify_segment([segment | _], route, _acc) when is_binary(segment) do
     raise ArgumentError,
-          "path segments must begin with /, got: #{inspect(segment)} in #{Macro.to_string(route)}"
+          "path segments after interpolation must begin with /, got: #{inspect(segment)} in #{Macro.to_string(route)}"
   end
 
   defp verify_segment(
@@ -711,7 +719,7 @@ defmodule Phoenix.VerifiedRoutes do
 
   defp rewrite_path(route, endpoint, router, statics) do
     {:<<>>, meta, segments} = route
-    {path_rewrite, query_rewrite} = verify_segment(segments, route, [])
+    {path_rewrite, query_rewrite} = verify_segment(segments, route)
 
     rewrite_route =
       quote generated: true do


Test patch:
diff --git a/guides/testing/testing.md b/guides/testing/testing.md
index 136d40f9a..2e85cb311 100644
--- a/guides/testing/testing.md
+++ b/guides/testing/testing.md
@@ -145,7 +145,7 @@ The error view test case, `test/hello_web/controllers/error_html_test.exs`, illu
 defmodule HelloWeb.ErrorHTMLTest do
   use HelloWeb.ConnCase, async: true
 
-  # Bring render_to_string/3 for testing custom views
+  # Bring render_to_string/4 for testing custom views
   import Phoenix.Template
 
   test "renders 404.html" do
@@ -337,18 +337,18 @@ defmodule HelloWeb.ErrorHTMLTest do
 
   @moduletag :error_view_case
 
-  # Bring render/3 and render_to_string/3 for testing custom views
-  import Phoenix.View
+  # Bring render/4 and render_to_string/4 for testing custom views
+  import Phoenix.Template
 
   @tag individual_test: "yup"
   test "renders 404.html" do
-    assert render_to_string(HelloWeb.ErrorView, "404.html", []) ==
+    assert render_to_string(HelloWeb.ErrorView, "404", "html", []) ==
            "Not Found"
   end
 
   @tag individual_test: "nope"
   test "renders 500.html" do
-    assert render_to_string(HelloWeb.ErrorView, "500.html", []) ==
+    assert render_to_string(HelloWeb.ErrorView, "500", "html", []) ==
            "Internal Server Error"
   end
 end
diff --git a/installer/templates/phx_test/controllers/error_html_test.exs b/installer/templates/phx_test/controllers/error_html_test.exs
index 965e5892e..6d3396470 100644
--- a/installer/templates/phx_test/controllers/error_html_test.exs
+++ b/installer/templates/phx_test/controllers/error_html_test.exs
@@ -1,7 +1,7 @@
 defmodule <%= @web_namespace %>.ErrorHTMLTest do
   use <%= @web_namespace %>.ConnCase, async: true
 
-  # Bring render_to_string/3 for testing custom views
+  # Bring render_to_string/4 for testing custom views
   import Phoenix.Template
 
   test "renders 404.html" do
diff --git a/test/phoenix/verified_routes_test.exs b/test/phoenix/verified_routes_test.exs
index 558c3e796..53e5d3b7b 100644
--- a/test/phoenix/verified_routes_test.exs
+++ b/test/phoenix/verified_routes_test.exs
@@ -201,7 +201,7 @@ defmodule Phoenix.VerifiedRoutesTest do
 
   test "~p raises when not prefixed by /" do
     assert_raise ArgumentError,
-                 ~s|path segments must begin with /, got: "posts/1" in "posts/1"|,
+                 ~s|paths must begin with /, got: "posts/1"|,
                  fn ->
                    defmodule SigilPPrefix do
                      use Phoenix.VerifiedRoutes,