Repository: phoenixframework/phoenix
Pull request #4981 (2022-09-26 02:39:17)

Use schema for atom names in auth templates.
I ran the generator with `mix phx.gen.auth Accounts Player players` and my tests were failing because the templates are hard coded to `:user`.

```
test register player renders errors for duplicated email (TankTurnTacticsWeb.PlayerRegistrationLiveTest)
     test/tank_turn_tactics_web/live/player_registration_live_test.exs:58
     ** (ArgumentError) could not find non-disabled input, select or textarea with name "player[email]" within:
```

The old form was using schema so it seems like the `:user` was an oversight in https://github.com/phoenixframework/phoenix/pull/4955/files#diff-2e85c1d43c43cc817baa18f588d767a32cda37aa39425e44aa6e488237d147e1

I though about adding a test for a mix call with different names but I figure if user still works then the code is correct. I smoke tested it in my app and it worked.



Patch:
diff --git a/installer/templates/phx_web/components.ex b/installer/templates/phx_web/components.ex
index 897d4fe7f..b3dd2457a 100644
--- a/installer/templates/phx_web/components.ex
+++ b/installer/templates/phx_web/components.ex
@@ -24,7 +24,7 @@ defmodule <%= @web_namespace %>.Components do
         Are you sure?
         <:confirm>OK</:confirm>
         <:cancel>Cancel</:cancel>
-      <.modal>
+      </.modal>
 
   JS commands may be passed to the `:on_cancel` and `on_confirm` attributes
   for the caller to reactor to each button press, for example:
@@ -32,8 +32,8 @@ defmodule <%= @web_namespace %>.Components do
       <.modal id="confirm" on_confirm={JS.push("delete")} on_cancel={JS.navigate(~p"/posts")}>
         Are you sure you?
         <:confirm>OK</:confirm>
-        <:cancel>Cancel</:confirm>
-      <.modal>
+        <:cancel>Cancel</:cancel>
+      </.modal>
   """
   attr :id, :string, required: true
   attr :show, :boolean, default: false
@@ -126,10 +126,10 @@ defmodule <%= @web_namespace %>.Components do
   attr :id, :string, default: "flash", doc: "the optional id of flash container"
   attr :flash, :map, default: %{}, doc: "the map of flash messages to display"
   attr :title, :string, default: nil
-  attr :rest, :global
-  attr :kind, :atom, doc: "one of :info, :error used for styling and flash lookup"
+  attr :kind, :atom, values: [:info, :error], doc: "Used for styling and flash lookup"
   attr :autoshow, :boolean, default: true, doc: "whether to auto show the flash on mount"
   attr :close, :boolean, default: true, doc: "whether the flash can be closed"
+  attr :rest, :global, doc: "the aribtrary HTML attributes to add to the flash container"
 
   slot :inner_block, doc: "the optional inner block that renders the flash message"
 
@@ -171,12 +171,14 @@ defmodule <%= @web_namespace %>.Components do
         <.input field={{f, :username}} label="Username" />
         <:actions>
           <.button>Save</.button>
-        <:actions>
+        </:actions>
       </.simple_form>
   """
   attr :for, :any, default: nil, doc: "the datastructure for the form"
   attr :as, :any, default: nil, doc: "the server side parameter to collect all input under"
-  attr :rest, :global, doc: "the arbitrary HTML attributes to apply to the form tag"
+  attr :rest, :global,
+    include: ~w(autocomplete name rel action enctype method novalidate target),
+    doc: "the arbitrary HTML attributes to apply to the form tag"
 
   slot :inner_block, required: true
   slot :actions, doc: "the slot for form actions, such as a submit button"
@@ -204,7 +206,7 @@ defmodule <%= @web_namespace %>.Components do
   """
   attr :type, :string, default: nil
   attr :class, :string, default: nil
-  attr :rest, :global, doc: "the arbitrary HTML attributes to apply to the button tag"
+  attr :rest, :global, include: ~w(disabled form name value)
 
   slot :inner_block, required: true
 
@@ -242,13 +244,14 @@ defmodule <%= @web_namespace %>.Components do
 
   attr :type, :string,
     default: "text",
-    doc: ~s|one of "text", "textarea", "number" "email", "date", "time", "datetime", "select"|
+    values: ~w(checkbox color date datetime-local email file hidden month number password
+               range radio search tel text time url week)
 
   attr :value, :any
   attr :field, :any, doc: "a %Phoenix.HTML.Form{}/field name tuple, for example: {f, :email}"
   attr :errors, :list
-  attr :rest, :global, doc: "the arbitrary HTML attributes for the input tag"
-
+  attr :rest, :global, include: ~w(autocomplete checked disabled form max maxlength min minlength
+                                   multiple pattern placeholder readonly required size step)
   slot :inner_block
   slot :option, doc: "the slot for select input options"
 
@@ -283,7 +286,6 @@ defmodule <%= @web_namespace %>.Components do
       <select
         id={@id}
         name={@name}
-        autocomplete={@name}
         class="mt-1 block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-zinc-500 focus:border-zinc-500 sm:text-sm"
         {@rest}
       >
diff --git a/lib/phoenix/endpoint/cowboy2_handler.ex b/lib/phoenix/endpoint/cowboy2_handler.ex
index cbedb17a8..727f944f2 100644
--- a/lib/phoenix/endpoint/cowboy2_handler.ex
+++ b/lib/phoenix/endpoint/cowboy2_handler.ex
@@ -24,25 +24,16 @@ defmodule Phoenix.Endpoint.Cowboy2Handler do
               cowboy_opts =
                 opts
                 |> Enum.flat_map(fn
-                  {:timeout, timeout} ->
-                    [idle_timeout: timeout]
-
-                  {:compress, _} = opt ->
-                    [opt]
-
-                  {:max_frame_size, _} = opt ->
-                    [opt]
-
-                  {:fullsweep_after, value} ->
-                    :erlang.process_flag(:fullsweep_after, value)
-                    []
-
-                  _other ->
-                    []
+                  {:timeout, timeout} -> [idle_timeout: timeout]
+                  {:compress, _} = opt -> [opt]
+                  {:max_frame_size, _} = opt -> [opt]
+                  _other -> []
                 end)
                 |> Map.new()
 
-              {:cowboy_websocket, copy_resp_headers(conn, req), [handler | state], cowboy_opts}
+              handler_opts = Keyword.take(opts, [:fullsweep_after])
+              triplet = {handler, handler_opts, state}
+              {:cowboy_websocket, copy_resp_headers(conn, req), triplet, cowboy_opts}
 
             {:error, %Plug.Conn{adapter: {@connection, req}} = conn} ->
               {:ok, copy_resp_headers(conn, req), {handler, opts}}
@@ -136,7 +127,11 @@ defmodule Phoenix.Endpoint.Cowboy2Handler do
 
   ## Websocket callbacks
 
-  def websocket_init([handler | state]) do
+  def websocket_init({handler, process_flags, state}) do
+    for {key, value} <- process_flags do
+      :erlang.process_flag(key, value)
+    end
+
     {:ok, state} = handler.init(state)
     {:ok, [handler | state]}
   end
diff --git a/priv/templates/phx.gen.auth/confirmation_live.ex b/priv/templates/phx.gen.auth/confirmation_live.ex
index 544d9d3df..f9924f2db 100644
--- a/priv/templates/phx.gen.auth/confirmation_live.ex
+++ b/priv/templates/phx.gen.auth/confirmation_live.ex
@@ -32,7 +32,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       {:ok, _} ->
         {:noreply,
          socket
-         |> put_flash(:info, "User confirmed successfully.")
+         |> put_flash(:info, "<%= inspect schema.alias %> confirmed successfully.")
          |> redirect(to: ~p"/")}
 
       :error ->
@@ -47,7 +47,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
           %{} ->
             {:noreply,
              socket
-             |> put_flash(:error, "User confirmation link is invalid or it has expired.")
+             |> put_flash(:error, "<%= inspect schema.alias %> confirmation link is invalid or it has expired.")
              |> redirect(to: ~p"/")}
         end
     end
diff --git a/priv/templates/phx.gen.auth/login_live.ex b/priv/templates/phx.gen.auth/login_live.ex
index 76c559127..605f7272b 100644
--- a/priv/templates/phx.gen.auth/login_live.ex
+++ b/priv/templates/phx.gen.auth/login_live.ex
@@ -18,9 +18,9 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       <.simple_form
         :let={f}
         id="login_form"
-        for={:user}
+        for={:<%= schema.singular %>}
         action={~p"<%= schema.route_prefix %>/log_in"}
-        as={:user}
+        as={:<%= schema.singular %>}
         phx-update="ignore"
       >
         <.input field={{f, :email}} type="email" label="Email" required />
diff --git a/priv/templates/phx.gen.auth/registration_live.ex b/priv/templates/phx.gen.auth/registration_live.ex
index b23e4e103..423d00511 100644
--- a/priv/templates/phx.gen.auth/registration_live.ex
+++ b/priv/templates/phx.gen.auth/registration_live.ex
@@ -27,7 +27,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         phx-trigger-action={@trigger_submit}
         action={~p"<%= schema.route_prefix %>/log_in?_action=registered"}
         method="post"
-        as={:user}
+        as={:<%= schema.singular %>}
       >
         <%%= if @changeset.action == :insert do %>
           <.error message="Oops, something went wrong! Please check the errors below." />
diff --git a/priv/templates/phx.gen.live/components.ex b/priv/templates/phx.gen.live/components.ex
index 897d4fe7f..056b3edd0 100644
--- a/priv/templates/phx.gen.live/components.ex
+++ b/priv/templates/phx.gen.live/components.ex
@@ -24,7 +24,7 @@ defmodule <%= @web_namespace %>.Components do
         Are you sure?
         <:confirm>OK</:confirm>
         <:cancel>Cancel</:cancel>
-      <.modal>
+      </.modal>
 
   JS commands may be passed to the `:on_cancel` and `on_confirm` attributes
   for the caller to reactor to each button press, for example:
@@ -32,8 +32,8 @@ defmodule <%= @web_namespace %>.Components do
       <.modal id="confirm" on_confirm={JS.push("delete")} on_cancel={JS.navigate(~p"/posts")}>
         Are you sure you?
         <:confirm>OK</:confirm>
-        <:cancel>Cancel</:confirm>
-      <.modal>
+        <:cancel>Cancel</:cancel>
+      </.modal>
   """
   attr :id, :string, required: true
   attr :show, :boolean, default: false
@@ -171,7 +171,7 @@ defmodule <%= @web_namespace %>.Components do
         <.input field={{f, :username}} label="Username" />
         <:actions>
           <.button>Save</.button>
-        <:actions>
+        </:actions>
       </.simple_form>
   """
   attr :for, :any, default: nil, doc: "the datastructure for the form"


Test patch:
diff --git a/priv/templates/phx.gen.auth/confirmation_live_test.exs b/priv/templates/phx.gen.auth/confirmation_live_test.exs
index 75b907e14..22abeb500 100644
--- a/priv/templates/phx.gen.auth/confirmation_live_test.exs
+++ b/priv/templates/phx.gen.auth/confirmation_live_test.exs
@@ -33,7 +33,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
       assert {:ok, conn} = result
       assert Phoenix.Flash.get(conn.assigns.flash, :info) =~
-        "User confirmed successfully"
+        "<%= inspect schema.alias %> confirmed successfully"
 
       assert <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= schema.singular %>.id).confirmed_at
       refute get_session(conn, :<%= schema.singular %>_token)
@@ -50,7 +50,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
       assert {:ok, conn} = result
       assert Phoenix.Flash.get(conn.assigns.flash, :error) =~
-        "User confirmation link is invalid or it has expired"
+        "<%= inspect schema.alias %> confirmation link is invalid or it has expired"
 
 
       # when logged in
@@ -81,7 +81,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         |> follow_redirect(conn, ~p"/")
 
       assert Phoenix.Flash.get(conn.assigns.flash, :error) =~
-        "User confirmation link is invalid or it has expired"
+        "<%= inspect schema.alias %> confirmation link is invalid or it has expired"
 
       refute <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= schema.singular %>.id).confirmed_at
     end