Repository: phoenixframework/phoenix
Pull request #4244 (2021-03-08 12:56:51)

Fix links in Views guide
Thery were introduced in 89a444e5c93b1c0c882a52b3fd650c74084051f6 #4224


Patch:
diff --git a/guides/controllers.md b/guides/controllers.md
index 97b04385a..d2e792c28 100644
--- a/guides/controllers.md
+++ b/guides/controllers.md
@@ -22,7 +22,7 @@ end
 
 The first line below the module definition invokes the `__using__/1` macro of the `HelloWeb` module, which imports some useful modules.
 
-The `PageController` gives us the `index` action to display the Phoenix [welcome page] associated with the default route Phoenix defines in the router.
+`PageController` gives us the `index` action to display the Phoenix [welcome page] associated with the default route Phoenix defines in the router.
 
 ## Actions
 
@@ -40,7 +40,7 @@ to `home`:
 get "/", PageController, :home
 ```
 
-as long as we change the action name in the `PageController` to `home` as well, the [welcome page] will load as before.
+as long as we change the action name in `PageController` to `home` as well, the [welcome page] will load as before.
 
 ```elixir
 defmodule HelloWeb.PageController do
@@ -144,7 +144,7 @@ defmodule HelloWeb.HelloController do
 end
 ```
 
-In order for the [`render/3`] function to work correctly, the controller and view must share the same root name (in this case `Hello`), and it also must have the same root name as the template directory (in this case `hello`) where the `show.html.eex` template lives. In other words, the `HelloController` requires `HelloView`, and `HelloView` requires the existence of the `lib/hello_web/templates/hello` directory, which must contain the `show.html.eex` template.
+In order for the [`render/3`] function to work correctly, the controller and view must share the same root name (in this case `Hello`), and it also must have the same root name as the template directory (in this case `hello`) where the `show.html.eex` template lives. In other words, `HelloController` requires `HelloView`, and `HelloView` requires the existence of the `lib/hello_web/templates/hello` directory, which must contain the `show.html.eex` template.
 
 [`render/3`] will also pass the value which the `show` action received for `messenger` from the parameters as an assign.
 
@@ -179,13 +179,13 @@ Generally speaking, once all assigns are configured, we invoke the view layer. T
 
 Layouts are just a special subset of templates. The live in the `templates/layout` folder (`lib/hello_web/templates/layout`). Phoenix created one for us when we generated our app. The default layout is called `app.html.eex`, and it is the layout into which all templates will be rendered by default.
 
-Since layouts are really just templates, they need a view to render them. This is the `LayoutView` module defined in `lib/hello_web/views/layout_view.ex`. Since Phoenix generated this view for us, we won't have to create a new one as long as we put the layouts we want to render inside the `lib/hello_web/templates/layout` directory.
+Since layouts are really just templates, they need a view to render them. This one is `LayoutView` which is defined in `lib/hello_web/views/layout_view.ex`. Since Phoenix generated this view for us, we won't have to create a new one as long as we put the layouts we want to render inside the `lib/hello_web/templates/layout` directory.
 
 Before we create a new layout, though, let's do the simplest possible thing and render a template with no layout at all.
 
 The `Phoenix.Controller` module provides the `put_layout/2` function for us to switch layouts. This takes `conn` as its first argument and a string for the basename of the layout we want to render. It also accepts `false` to disable the layout altogether.
 
-You can edit the `index` action of the `PageController` module in `lib/hello_web/controllers/page_controller.ex` to look like this.
+You can edit the `index` action of `PageController` in `lib/hello_web/controllers/page_controller.ex` to look like this.
 
 ```elixir
 def index(conn, _params) do
@@ -229,7 +229,7 @@ Rendering HTML through a template is fine, but what if we need to change the ren
 
 Phoenix allows us to change formats on the fly with the `_format` query string parameter. To make this happen, Phoenix requires an appropriately named view and an appropriately named template in the correct directory.
 
-As an example, let's take the `PageController` index action from a newly generated app. Out of the box, this has the right view `PageView`, the right templates directory (`lib/hello_web/templates/page`), and the right template for rendering HTML (`index.html.eex`.)
+As an example, let's take `PageController`'s `index` action from a newly generated app. Out of the box, this has the right view `PageView`, the right templates directory (`lib/hello_web/templates/page`), and the right template for rendering HTML (`index.html.eex`.)
 
 ```elixir
 def index(conn, _params) do
@@ -272,7 +272,7 @@ If we go to [`http://localhost:4000/?_format=text`](http://localhost:4000/?_form
 
 If none of the rendering options above quite fits our needs, we can compose our own using some of the functions that Plug gives us. Let's say we want to send a response with a status of "201" and no body whatsoever. We can easily do that with the `Plug.Conn.send_resp/3` function.
 
-Edit the `index` action of the `PageController` module `lib/hello_web/controllers/page_controller.ex` to look like this:
+Edit the `index` action of `PageController` in `lib/hello_web/controllers/page_controller.ex` to look like this:
 
 ```elixir
 def index(conn, _params) do
@@ -352,7 +352,7 @@ defmodule HelloWeb.Router do
 end
 ```
 
-Then we'll change the `PageController` `index` action of our controller to do nothing but to redirect to our new route.
+Then we'll change `PageController`'s `index` action of our controller to do nothing but to redirect to our new route.
 
 ```elixir
 defmodule HelloWeb.PageController do
@@ -445,7 +445,7 @@ Phoenix does not enforce which keys are stored in the flash. As long as we are i
 
 Action fallback allows us to centralize error handling code in plugs which are called when a controller action fails to return a [`%Plug.Conn{}`](https://hexdocs.pm/plug/Plug.Conn.html#t:t/0) struct. These plugs receive both the `conn` which was originally passed to the controller action along with the return value of the action.
 
-Let's say we have a `show` action which uses [`with`](`Kernel.SpecialForms.with/1`) to fetch a blog post and then authorize the current user to view that blog post. In this example we might expect `fetch_post/1` to return `{:error, :not_found}` if the post is not found and `authorize_user/3` might return `{:error, :unauthorized}` if the user is unauthorized. We could use the `ErrorView` module that Phoenix generates for every new application to handle these error paths accordingly:
+Let's say we have a `show` action which uses [`with`](`Kernel.SpecialForms.with/1`) to fetch a blog post and then authorize the current user to view that blog post. In this example we might expect `fetch_post/1` to return `{:error, :not_found}` if the post is not found and `authorize_user/3` might return `{:error, :unauthorized}` if the user is unauthorized. We could use `ErrorView` which is generated by Phoenix for every new application to handle these error paths accordingly:
 
 ```elixir
 defmodule HelloWeb.MyController do
diff --git a/guides/howto/custom_error_pages.md b/guides/howto/custom_error_pages.md
index 65771a750..9cde4b8fc 100644
--- a/guides/howto/custom_error_pages.md
+++ b/guides/howto/custom_error_pages.md
@@ -1,6 +1,6 @@
 # Custom Error Pages
 
-Phoenix has a view called the `ErrorView` which lives in `lib/hello_web/views/error_view.ex`. The purpose of `ErrorView` is to handle errors in a general way, from one centralized location.
+Phoenix has a view called `ErrorView` which lives in `lib/hello_web/views/error_view.ex`. The purpose of `ErrorView` is to handle errors in s.)
 
 ## The ErrorView
 
@@ -41,7 +41,7 @@ After modifying our config file, we need to restart our server in order for this
 
 Ok, that's not very exciting. We get the bare string "Not Found", displayed without any markup or styling.
 
-The first question is, where does that error string come from? The answer is right in the `ErrorView`.
+The first question is, where does that error string come from? The answer is right in `ErrorView`.
 
 ```elixir
 def template_not_found(template, _assigns) do
diff --git a/guides/request_lifecycle.md b/guides/request_lifecycle.md
index 1910fccd5..b80e9a74c 100644
--- a/guides/request_lifecycle.md
+++ b/guides/request_lifecycle.md
@@ -188,7 +188,7 @@ As we did last time, the first thing we'll do is create a new route.
 
 ### Another new route
 
-For this exercise, we're going to reuse the `HelloController` we just created and just add a new `show` action. We'll add a line just below our last route, like this:
+For this exercise, we're going to reuse `HelloController` which was just created and simply add a new `show` action. We'll add a line just below our last route, like this:
 
 ```elixir
 scope "/", HelloWeb do
@@ -226,7 +226,7 @@ It's good to remember that the keys of the `params` map will always be strings,
 
 ### Another new template
 
-For the last piece of this puzzle, we'll need a new template. Since it is for the `show` action of the `HelloController`, it will go into the `lib/hello_web/templates/hello` directory and be called `show.html.eex`. It will look surprisingly like our `index.html.eex` template, except that we will need to display the name of our messenger.
+For the last piece of this puzzle, we'll need a new template. Since it is for the `show` action of `HelloController`, it will go into the `lib/hello_web/templates/hello` directory and be called `show.html.eex`. It will look surprisingly like our `index.html.eex` template, except that we will need to display the name of our messenger.
 
 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. If the equals sign were missing, the code would still be executed, but the value would not appear on the page.
 
diff --git a/guides/routing.md b/guides/routing.md
index 6592c9c16..dc44ac545 100644
--- a/guides/routing.md
+++ b/guides/routing.md
@@ -238,7 +238,7 @@ user_post_path  DELETE  /users/:user_id/posts/:id       HelloWeb.PostController
 ...
 ```
 
-We see that each of these routes scopes the posts to a user ID. For the first one, we will invoke the `PostController` `index` action, but we will pass in a `user_id`. This implies that we would display all the posts for that individual user only. The same scoping applies for all these routes.
+We see that each of these routes scopes the posts to a user ID. For the first one, we will invoke `PostController`'s `index` action, but we will pass in a `user_id`. This implies that we would display all the posts for that individual user only. The same scoping applies for all these routes.
 
 When calling path helper functions for nested routes, we will need to pass the IDs in the order they came in the route definition. For the following `show` route, `42` is the `user_id`, and `17` is the `post_id`. Let's remember to alias our `HelloWeb.Endpoint` before we begin.
 
@@ -543,7 +543,7 @@ end
 
 When the server accepts a request, the request will always first pass through the plugs in our endpoint, after which it will attempt to match on the path and HTTP verb.
 
-Let's say that the request matches our first route: a GET to `/`. The router will first pipe that request through the `:browser` pipeline - which will fetch the session data, fetch the flash, and execute forgery protection - before it dispatches the request to the `PageController` `index` action.
+Let's say that the request matches our first route: a GET to `/`. The router will first pipe that request through the `:browser` pipeline - which will fetch the session data, fetch the flash, and execute forgery protection - before it dispatches the request to `PageController`'s `index` action.
 
 Conversely, if the request matches any of the routes defined by the `resources/2` macro, the router will pipe it through the `:api` pipeline — which currently does nothing — before it dispatches further to the correct action of the `HelloWeb.ReviewController`.
 
diff --git a/guides/views.md b/guides/views.md
index e74b045de..a178790b4 100644
--- a/guides/views.md
+++ b/guides/views.md
@@ -8,11 +8,11 @@ The main job of a Phoenix view is to render the body of the response which gets
 
 ## Rendering templates
 
-Phoenix assumes a strong naming convention from controllers to views to the templates they render. The `PageController` controller requires a `PageView` view to render templates in the `lib/hello_web/templates/page/` directory. While all of these can be customizable (see `Phoenix.View` and `Phoenix.Template` for more information), we recommend users stick with Phoenix' convention.
+Phoenix assumes a strong naming convention from controllers to views to the templates they render. `PageController` requires a `PageView` to render templates in the `lib/hello_web/templates/page/` directory. While all of these can be customizable (see `Phoenix.View` and `Phoenix.Template` for more information), we recommend users stick with Phoenix' convention.
 
 A newly generated Phoenix application has three view modules - `ErrorView`, `LayoutView`, and `PageView` -  which are all in the `lib/hello_web/views/` directory.
 
-Let's take a quick look at the `LayoutView` view.
+Let's take a quick look at `LayoutView`.
 
 ```elixir
 defmodule HelloWeb.LayoutView do
@@ -267,7 +267,8 @@ defmodule HelloWeb.PageView do
 end
 ```
 
-The name used in assigns is determined from the view. For example the `PageView` view will use `%{page: page}` and the `AuthorView` view will use `%{author: author}`. This can be overridden with the `as` option. Let's assume that the author view uses `%{writer: writer}` instead of `%{author: author}`:
+The name used in assigns is determined from the view. For example `PageView` will use `%{page: page}` and `AuthorView` will use `%{author: author}`. This can be overridden with the `as` option. Let's assume that the author view uses `%{writer: writer}` instead of `%{author: author}`:
+>>>>>>> ff14fd75 (Fix grammar. Remove article "the" before controllers and views.)
 
 ```elixir
 def render("page_with_authors.json", %{page: page}) do
@@ -278,12 +279,12 @@ end
 
 ## Error pages
 
-Phoenix has a view called the `ErrorView` which lives in `lib/hello_web/views/error_view.ex`. The purpose of `ErrorView` is to handle errors in a general way, from one centralized location.  Similar to the views we built in this guide, error views can return both HTML and JSON responses. See the [custom error pages how-to](custom_error_pages.html) for more information.
+Phoenix has a view called `ErrorView` which lives in `lib/hello_web/views/error_view.ex`. The purpose of `ErrorView` is to handle errors in a general way, from one centralized location.  Similar to the views we built in this guide, error views can return both HTML and JSON responses. See the [Custom Error Pages How-To](custom_error_pages.html) for more information.
 
 
 [welcome page]: http://localhost:4000
-[`render/2`]: Phoenix.View.render/3
-[`render/3`]: Phoenix.View.render/3
-[`render_many/3`]: Phoenix.View.render_many/3
-[`render_one/3`]: Phoenix.View.render_one/3
-[`render_to_string/3`]: Phoenix.View.render_to_string/3
+[`render/2`]: `Phoenix.View.render/3`
+[`render/3`]: `Phoenix.View.render/3`
+[`render_many/3`]: `Phoenix.View.render_many/3`
+[`render_one/3`]: `Phoenix.View.render_one/3`
+[`render_to_string/3`]: `Phoenix.View.render_to_string/3`
diff --git a/lib/mix/tasks/phx.gen.auth.ex b/lib/mix/tasks/phx.gen.auth.ex
index 52c27a510..fdb975ee9 100644
--- a/lib/mix/tasks/phx.gen.auth.ex
+++ b/lib/mix/tasks/phx.gen.auth.ex
@@ -276,6 +276,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth do
 
     paths
     |> Mix.Phoenix.eval_from("priv/templates/phx.gen.auth/context_fixtures_functions.ex", binding)
+    |> prepend_newline()
     |> inject_before_final_end(test_fixtures_file)
   end
 
diff --git a/lib/phoenix/controller.ex b/lib/phoenix/controller.ex
index 20f9dc131..496a6e5fb 100644
--- a/lib/phoenix/controller.ex
+++ b/lib/phoenix/controller.ex
@@ -118,7 +118,7 @@ defmodule Phoenix.Controller do
 
   which will trigger the plug pipeline and which will eventually
   invoke the inner action plug that dispatches to the `show/2`
-  function in the `UserController`.
+  function in `UserController`.
 
   As controllers are plugs, they implement both [`init/1`](`c:Plug.init/1`) and
   [`call/2`](`c:Plug.call/2`), and it also provides a function named `action/2`
diff --git a/lib/phoenix/router.ex b/lib/phoenix/router.ex
index 2402c49b5..73052766a 100644
--- a/lib/phoenix/router.ex
+++ b/lib/phoenix/router.ex
@@ -36,7 +36,7 @@ defmodule Phoenix.Router do
       end
 
   The `get/3` macro above accepts a request to `/pages/hello` and dispatches
-  it to the `PageController`'s `show` action with `%{"page" => "hello"}` in
+  it to `PageController`'s `show` action with `%{"page" => "hello"}` in
   `params`.
 
   Phoenix's router is extremely efficient, as it relies on Elixir
diff --git a/priv/templates/phx.gen.auth/context_fixtures_functions.ex b/priv/templates/phx.gen.auth/context_fixtures_functions.ex
index ec909a30d..fd53675ba 100644
--- a/priv/templates/phx.gen.auth/context_fixtures_functions.ex
+++ b/priv/templates/phx.gen.auth/context_fixtures_functions.ex
@@ -1,14 +1,17 @@
-
   def unique_<%= schema.singular %>_email, do: "<%= schema.singular %>#{System.unique_integer()}@example.com"
   def valid_<%= schema.singular %>_password, do: "hello world!"
 
+  def valid_<%= schema.singular %>_attributes(attrs \\ %{}) do
+    Enum.into(attrs, %{
+      email: unique_<%= schema.singular %>_email(),
+      password: valid_<%= schema.singular %>_password()
+    })
+  end
+
   def <%= schema.singular %>_fixture(attrs \\ %{}) do
     {:ok, <%= schema.singular %>} =
       attrs
-      |> Enum.into(%{
-        email: unique_<%= schema.singular %>_email(),
-        password: valid_<%= schema.singular %>_password()
-      })
+      |> valid_<%= schema.singular %>_attributes()
       |> <%= inspect context.module %>.register_<%= schema.singular %>()
 
     <%= schema.singular %>


Test patch:
diff --git a/guides/testing/testing_controllers.md b/guides/testing/testing_controllers.md
index b2c6d965d..4112c4931 100644
--- a/guides/testing/testing_controllers.md
+++ b/guides/testing/testing_controllers.md
@@ -341,13 +341,13 @@ def create(conn, %{"article" => article_params}) do
 
 The `with` special form that ships as part of Elixir allows us to check explicitly for the happy paths. In this case, we are interested only in the scenarios where `News.create_article(article_params)` returns `{:ok, article}`, if it returns anything else, the other value will simply be returned directly and none of the contents inside the `do/end` block will be executed. In other words, if `News.create_article/1` returns `{:error, changeset}`, we will simply return `{:error, changeset}` from the action.
 
-However, this introduces an issue. Our actions do not know how to handle the `{:error, changeset}` result by default. Luckily, we can teach Phoenix Controllers to handle it with the Action Fallback controller. At the top of the `ArticleController`, you will find:
+However, this introduces an issue. Our actions do not know how to handle the `{:error, changeset}` result by default. Luckily, we can teach Phoenix Controllers to handle it with the Action Fallback controller. At the top of `ArticleController`, you will find:
 
 ```elixir
   action_fallback HelloWeb.FallbackController
 ```
 
-This line says: if any action does not return a `%Plug.Conn{}`, we want to invoke the `FallbackController` with the result. You will find `HelloWeb.FallbackController` at `lib/hello_web/controllers/fallback_controller.ex` and it looks like this:
+This line says: if any action does not return a `%Plug.Conn{}`, we want to invoke `FallbackController` with the result. You will find `HelloWeb.FallbackController` at `lib/hello_web/controllers/fallback_controller.ex` and it looks like this:
 
 ```elixir
 defmodule HelloWeb.FallbackController do
diff --git a/priv/templates/phx.gen.auth/registration_controller_test.exs b/priv/templates/phx.gen.auth/registration_controller_test.exs
index 4daf6ec12..02ac94dd4 100644
--- a/priv/templates/phx.gen.auth/registration_controller_test.exs
+++ b/priv/templates/phx.gen.auth/registration_controller_test.exs
@@ -25,7 +25,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
       conn =
         post(conn, Routes.<%= schema.route_helper %>_registration_path(conn, :create), %{
-          "<%= schema.singular %>" => %{"email" => email, "password" => valid_<%= schema.singular %>_password()}
+          "<%= schema.singular %>" => valid_<%= schema.singular %>_attributes(email: email)
         })
 
       assert get_session(conn, :<%= schema.singular %>_token)
diff --git a/priv/templates/phx.gen.auth/test_cases.exs b/priv/templates/phx.gen.auth/test_cases.exs
index 8a0fa67a4..a29397e13 100644
--- a/priv/templates/phx.gen.auth/test_cases.exs
+++ b/priv/templates/phx.gen.auth/test_cases.exs
@@ -81,7 +81,7 @@
 
     test "registers <%= schema.plural %> with a hashed password" do
       email = unique_<%= schema.singular %>_email()
-      {:ok, <%= schema.singular %>} = <%= inspect context.alias %>.register_<%= schema.singular %>(%{email: email, password: valid_<%= schema.singular %>_password()})
+      {:ok, <%= schema.singular %>} = <%= inspect context.alias %>.register_<%= schema.singular %>(valid_<%= schema.singular %>_attributes(email: email))
       assert <%= schema.singular %>.email == email
       assert is_binary(<%= schema.singular %>.hashed_password)
       assert is_nil(<%= schema.singular %>.confirmed_at)
@@ -100,7 +100,10 @@
       password = valid_<%= schema.singular %>_password()
 
       changeset =
-        <%= inspect context.alias %>.change_<%= schema.singular %>_registration(%<%= inspect schema.alias %>{}, %{"email" => email, "password" => password})
+        <%= inspect context.alias %>.change_<%= schema.singular %>_registration(
+          %<%= inspect schema.alias %>{},
+          valid_<%= schema.singular %>_attributes(email: email, password: password)
+        )
 
       assert changeset.valid?
       assert get_change(changeset, :email) == email
diff --git a/test/mix/tasks/phx.gen.auth_test.exs b/test/mix/tasks/phx.gen.auth_test.exs
index 1eac38a1d..7f6d173d7 100644
--- a/test/mix/tasks/phx.gen.auth_test.exs
+++ b/test/mix/tasks/phx.gen.auth_test.exs
@@ -217,7 +217,10 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
       assert_file "lib/my_app/accounts/user_token.ex"
       assert_file "lib/my_app/accounts/user_notifier.ex"
       assert_file "test/my_app/accounts_test.exs"
-      assert_file "test/support/fixtures/accounts_fixtures.ex"
+
+      assert_file "test/support/fixtures/accounts_fixtures.ex", fn file ->
+        assert file =~ ~s|def valid_user_attributes(attrs \\\\ %{}) do|
+      end
 
       assert_file "lib/my_app_web/controllers/warehouse/user_auth.ex", fn file ->
         assert file =~ "defmodule MyAppWeb.Warehouse.UserAuth do"