Repository: phoenixframework/phoenix
Pull request #3736 (2020-04-02 21:57:40)

Add phx.gen.live to list of context-related generators
This adds `phx.gen.live` to the list of context-related generators (`phx.gen.html`, `phx.gen.json` and `phx.gen.context`) everywhere they're listed together.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 326a18d8f..e6c8ee234 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,12 +15,13 @@ Phoenix built-in guides have been restructured and revamped, providing a better
 ### Enhancements
 
   * [Channel] Do not block the channel supervisor on join
+  * [ConnTest] Add `init_test_session` to Phoenix.ConnTest
   * [Controller] Support `:disposition` option in `send_download/3`
   * [Endpoint] Allow named params to be used when defining socket paths
   * [Endpoint] Raise if `force_ssl` has changed from compile time to runtime
+  * [Generator] Add `mix phx.gen.live`
   * [PubSub] Migrate to PubSub 2.0 with a more flexible fastlaning mechanism
-
-### Bug Fixes
+  * [View] Add `render_layout` which makes it easy to work with nested layouts
 
 ### Deprecations
 
@@ -28,6 +29,8 @@ Phoenix built-in guides have been restructured and revamped, providing a better
   * [ConnTest] `use Phoenix.ConnTest` is deprecated in favor of `import Plug.Conn; import Phoenix.ConnTest`
   * [Endpoint] The outdated `Phoenix.Endpoint.CowboyAdapter` for Cowboy 1 is deprecated. Please make sure `{:plug_cowboy, "~> 2.1"}` or later is listed in your `mix.exs`
   * [Endpoint] `subscribe` and `unsubscribe` via the endpoint is deprecated, please use `Phoenix.PubSub` directly instead
+  * [Endpoint] `Phoenix.Endpoint.instrument/4` is deprecated and has no effect. Use `:telemetry` instead. See `Phoenix.Logger` for more information
+  * [Endpoint] The `:pubsub` key for endpoint is deprecated. Once you start your app, you will see step-by-step instructions on how to use the new PubSub config
   * [Layout] Use `<%= @inner_content %>` instead of `<%= render @view_module, @view_template, assigns %>` for rendering the child layout
 
 ### phx.new installer
@@ -36,9 +39,12 @@ Phoenix built-in guides have been restructured and revamped, providing a better
   * `Phoenix.PubSub` is now started directly in your application supervision tree
   * `Phoenix.Ecto.CheckRepoStatus` is now added to new applications that use Ecto
   * Automatically use `System.get_env("MIX_TEST_PARTITION")` in the database name in the test environemnt for built-in CI test partitioning
+  * Generate a `MyApp.Telemetry` module with examples of Telemetry Metrics you may want to track in your app
+  * Support the `--live` flag for generating apps with out-of-the-box LiveView support
 
 ### JavaScript client
 
+  * Ensure all channel event listeners are called
 
 ## v1.4
 
diff --git a/guides/contexts.md b/guides/contexts.md
index 61378c81a..46475dc23 100644
--- a/guides/contexts.md
+++ b/guides/contexts.md
@@ -24,7 +24,7 @@ Let's use these ideas to build out our web application. Our goal is to build a u
 
 User accounts are often wide-reaching across a platform so it's important to think upfront about writing a well-defined interface. With that in mind, our goal is to build an accounts API that handles creating, updating, and deleting user accounts, as well as authenticating user credentials. We'll start off with basic features, but as we add authentication later, we'll see how starting with a solid foundation allows us to grow our application naturally as we add functionality.
 
-Phoenix includes the `phx.gen.html`, `phx.gen.json`, and `phx.gen.context` generators that apply the ideas of isolating functionality in our applications into contexts. These generators are a great way to hit the ground running while Phoenix nudges you in the right direction to grow your application. Let's put these tools to use for our new user accounts context.
+Phoenix includes the `phx.gen.html`, `phx.gen.json`, `phx.gen.live`, and `phx.gen.context` generators that apply the ideas of isolating functionality in our applications into contexts. These generators are a great way to hit the ground running while Phoenix nudges you in the right direction to grow your application. Let's put these tools to use for our new user accounts context.
 
 In order to run the context generators, we need to come up with a module name that groups the related functionality that we're building. In the [Ecto guide](ecto.html), we saw how we can use Changesets and Repos to validate and persist user schemas, but we didn't integrate this with our application at large. In fact, we didn't think about where a "user" in our application should live at all. Let's take a step back and think about the different parts of our system. We know that we'll have users of our product. Along with users comes things like account login credentials and user registration. An `Accounts` context in our system is a natural place for our user functionality to live.
 
diff --git a/guides/deployment/heroku.md b/guides/deployment/heroku.md
index a0bf6c36d..be9279ebd 100644
--- a/guides/deployment/heroku.md
+++ b/guides/deployment/heroku.md
@@ -115,14 +115,11 @@ Buildpack added. Next release on mysterious-meadow-6277 will use:
   2. https://github.com/gjaldon/heroku-buildpack-phoenix-static.git
 ```
 
-The Phoenix Static buildpack uses a predefined Node and NPM version but to avoid surprises when deploying, it is best to explicitly list the Node and NPM version we want in production to be the same we are using during development or in your continuous integration servers. This is done by creating a config file named `phoenix_static_buildpack.config` in the root directory of your project with your target version of Node and NPM:
+The Phoenix Static buildpack uses a predefined Node version but to avoid surprises when deploying, it is best to explicitly list the Node version we want in production to be the same we are using during development or in your continuous integration servers. This is done by creating a config file named `phoenix_static_buildpack.config` in the root directory of your project with your target version of Node:
 
 ```
 # Node version
-node_version=10.15.3
-
-# NPM version
-npm_version=6.14.2
+node_version=10.19.0
 ```
 
 Please refer to the [configuration section](https://github.com/gjaldon/heroku-buildpack-phoenix-static#configuration) for full details. You can make your own custom build script, but for now we will use the [default one provided](https://github.com/gjaldon/heroku-buildpack-phoenix-static/blob/master/compile).
diff --git a/installer/lib/mix/tasks/phx.new.ex b/installer/lib/mix/tasks/phx.new.ex
index f49e85636..4ccdde4e4 100644
--- a/installer/lib/mix/tasks/phx.new.ex
+++ b/installer/lib/mix/tasks/phx.new.ex
@@ -52,8 +52,8 @@ defmodule Mix.Tasks.Phx.New do
     * `--verbose` - use verbose output
 
   When passing the `--no-ecto` flag, Phoenix generators such as
-  `phx.gen.html`, `phx.gen.json` and `phx.gen.context` may no
-  longer work as expected as they generate context files that rely
+  `phx.gen.html`, `phx.gen.json`, `phx.gen.live`, and `phx.gen.context`
+  may no longer work as expected as they generate context files that rely
   on Ecto for the database access. In those cases, you can pass the
   `--no-context` flag to generate most of the HTML and JSON files
   but skip the context, allowing you to fill in the blanks as desired.
diff --git a/installer/lib/phx_new/single.ex b/installer/lib/phx_new/single.ex
index b4f37ee4e..2360573a8 100644
--- a/installer/lib/phx_new/single.ex
+++ b/installer/lib/phx_new/single.ex
@@ -50,7 +50,7 @@ defmodule Phx.New.Single do
 
   template :live, [
     {:eex, "phx_live/templates/layout/root.html.leex",       :project, "lib/:lib_web_name/templates/layout/root.html.leex"},
-    {:eex, "phx_live/templates/layout/app.html.leex",        :project, "lib/:lib_web_name/templates/layout/app.html.leex"},
+    {:eex, "phx_live/templates/layout/app.html.leex",        :project, "lib/:lib_web_name/templates/layout/app.html.eex"},
     {:eex, "phx_live/templates/layout/live.html.leex",       :project, "lib/:lib_web_name/templates/layout/live.html.leex"},
     {:eex, "phx_web/views/layout_view.ex",                   :project, "lib/:lib_web_name/views/layout_view.ex"},
     {:eex, "phx_live/live/page_live.ex",                     :project, "lib/:lib_web_name/live/page_live.ex"},
diff --git a/installer/lib/phx_new/web.ex b/installer/lib/phx_new/web.ex
index 11192f5ad..525d5318a 100644
--- a/installer/lib/phx_new/web.ex
+++ b/installer/lib/phx_new/web.ex
@@ -51,7 +51,7 @@ defmodule Phx.New.Web do
 
   template :live, [
     {:eex, "phx_live/templates/layout/root.html.leex", :web, "lib/:web_app/templates/layout/root.html.leex"},
-    {:eex, "phx_live/templates/layout/app.html.leex",  :web, "lib/:web_app/templates/layout/app.html.leex"},
+    {:eex, "phx_live/templates/layout/app.html.leex",  :web, "lib/:web_app/templates/layout/app.html.eex"},
     {:eex, "phx_live/templates/layout/live.html.leex", :web, "lib/:web_app/templates/layout/live.html.leex"},
     {:eex, "phx_web/views/layout_view.ex",             :web, "lib/:web_app/views/layout_view.ex"},
     {:eex, "phx_live/live/page_live.ex",               :web, "lib/:web_app/live/page_live.ex"},
diff --git a/installer/templates/phx_single/mix.exs b/installer/templates/phx_single/mix.exs
index e1bdba863..1d4d2565a 100644
--- a/installer/templates/phx_single/mix.exs
+++ b/installer/templates/phx_single/mix.exs
@@ -41,7 +41,7 @@ defmodule <%= app_module %>.MixProject do
       {:phoenix_ecto, "~> 4.1"},
       {:ecto_sql, "~> 3.4"},
       {<%= inspect adapter_app %>, ">= 0.0.0"},<% end %><%= if html do %><%= if live do %>
-      {:phoenix_live_view, "~> 0.10.0"},
+      {:phoenix_live_view, "~> 0.11.0"},
       {:floki, ">= 0.0.0", only: :test},<% end %><%= if dashboard do %>
       {:phoenix_live_dashboard, github: "phoenixframework/phoenix_live_dashboard"},<% end %>
       {:phoenix_html, "~> 2.11"},
diff --git a/installer/templates/phx_umbrella/apps/app_name_web/mix.exs b/installer/templates/phx_umbrella/apps/app_name_web/mix.exs
index afcce74a2..84f75607e 100644
--- a/installer/templates/phx_umbrella/apps/app_name_web/mix.exs
+++ b/installer/templates/phx_umbrella/apps/app_name_web/mix.exs
@@ -39,7 +39,7 @@ defmodule <%= web_namespace %>.MixProject do
     [
       <%= phoenix_dep %>,<%= if ecto do %>
       {:phoenix_ecto, "~> 4.0"},<% end %><%= if html do %><%= if live do %>
-      {:phoenix_live_view, "~> 0.10.0"},
+      {:phoenix_live_view, "~> 0.11.0"},
       {:floki, ">= 0.0.0", only: :test},<% end %><%= if dashboard do %>
       {:phoenix_live_dashboard, github: "phoenixframework/phoenix_live_dashboard"},<% end %>
       {:phoenix_html, "~> 2.11"},
diff --git a/lib/mix/tasks/phx.gen.context.ex b/lib/mix/tasks/phx.gen.context.ex
index 19aea6c47..9f57e2cd7 100644
--- a/lib/mix/tasks/phx.gen.context.ex
+++ b/lib/mix/tasks/phx.gen.context.ex
@@ -100,11 +100,11 @@ defmodule Mix.Tasks.Phx.Gen.Context do
   end
 
   @doc false
-  def build(args) do
+  def build(args, help \\ __MODULE__) do
     {opts, parsed, _} = parse_opts(args)
-    [context_name, schema_name, plural | schema_args] = validate_args!(parsed)
+    [context_name, schema_name, plural | schema_args] = validate_args!(parsed, help)
     schema_module = inspect(Module.concat(context_name, schema_name))
-    schema = Gen.Schema.build([schema_module, plural | schema_args], opts, __MODULE__)
+    schema = Gen.Schema.build([schema_module, plural | schema_args], opts, help)
     context = Context.new(context_name, schema, opts)
     {context, schema}
   end
@@ -200,25 +200,25 @@ defmodule Mix.Tasks.Phx.Gen.Context do
     end
   end
 
-  defp validate_args!([context, schema, _plural | _] = args) do
+  defp validate_args!([context, schema, _plural | _] = args, help) do
     cond do
       not Context.valid?(context) ->
-        raise_with_help "Expected the context, #{inspect context}, to be a valid module name"
+        help.raise_with_help "Expected the context, #{inspect context}, to be a valid module name"
       not Schema.valid?(schema) ->
-        raise_with_help "Expected the schema, #{inspect schema}, to be a valid module name"
+        help.raise_with_help "Expected the schema, #{inspect schema}, to be a valid module name"
       context == schema ->
-        raise_with_help "The context and schema should have different names"
+        help.raise_with_help "The context and schema should have different names"
       context == Mix.Phoenix.base() ->
-        raise_with_help "Cannot generate context #{context} because it has the same name as the application"
+        help.raise_with_help "Cannot generate context #{context} because it has the same name as the application"
       schema == Mix.Phoenix.base() ->
-        raise_with_help "Cannot generate schema #{schema} because it has the same name as the application"
+        help.raise_with_help "Cannot generate schema #{schema} because it has the same name as the application"
       true ->
         args
     end
   end
 
-  defp validate_args!(_) do
-    raise_with_help "Invalid arguments"
+  defp validate_args!(_, help) do
+    help.raise_with_help "Invalid arguments"
   end
 
   @doc false
@@ -227,13 +227,14 @@ defmodule Mix.Tasks.Phx.Gen.Context do
     Mix.raise """
     #{msg}
 
-    mix phx.gen.html, phx.gen.json and phx.gen.context expect a
-    context module name, followed by singular and plural names of
-    the generated resource, ending with any number of attributes.
+    mix phx.gen.html, phx.gen.json, phx.gen.live, and phx.gen.context
+    expect a context module name, followed by singular and plural names
+    of the generated resource, ending with any number of attributes.
     For example:
 
         mix phx.gen.html Accounts User users name:string
         mix phx.gen.json Accounts User users name:string
+        mix phx.gen.live Accounts User users name:string
         mix phx.gen.context Accounts User users name:string
 
     The context serves as the API boundary for the given resource.
diff --git a/lib/mix/tasks/phx.gen.presence.ex b/lib/mix/tasks/phx.gen.presence.ex
index e36389ced..b1ef32314 100644
--- a/lib/mix/tasks/phx.gen.presence.ex
+++ b/lib/mix/tasks/phx.gen.presence.ex
@@ -2,17 +2,16 @@ defmodule Mix.Tasks.Phx.Gen.Presence do
   @shortdoc "Generates a Presence tracker"
 
   @moduledoc """
-  Generates a Presence tracker for your application.
+  Generates a Presence tracker.
 
       mix phx.gen.presence
-
       mix phx.gen.presence MyPresence
 
-  The only argument is the module name of the Presence tracker,
-  which defaults to Presence.
+  The argument, which defaults to `Presence`, defines the module name of the
+  Presence tracker.
 
-  A new file will be generated in `lib/my_app_web/channels/presence.ex`,
-  where `my_app_web` is the snake cased version of the module name provided.
+  Generates a new file, `lib/my_app_web/channels/my_presence.ex`, where
+  `my_presence` is the snake-cased version of the provided module name.
   """
   use Mix.Task
 
diff --git a/lib/phoenix/controller.ex b/lib/phoenix/controller.ex
index 4a5d5b3b1..4058319c2 100644
--- a/lib/phoenix/controller.ex
+++ b/lib/phoenix/controller.ex
@@ -757,19 +757,7 @@ defmodule Phoenix.Controller do
     render(conn, view, template, [])
   end
 
-  @doc """
-  WARNING: This function is deprecated in favor of `render/3` + `put_view/2`.
-
-  A shortcut that renders the given template in the given view.
-
-  Equivalent to:
-
-      conn
-      |> put_view(view)
-      |> render(template, assigns)
-
-  """
-  @spec render(Plug.Conn.t, atom, atom | binary, Keyword.t | map) :: Plug.Conn.t
+  @doc false
   def render(conn, view, template, assigns)
       when is_atom(view) and (is_binary(template) or is_atom(template)) do
     IO.warn "#{__MODULE__}.render/4 with a view is deprecated, see the documentation for render/3 for an alternative"
diff --git a/lib/phoenix/endpoint.ex b/lib/phoenix/endpoint.ex
index 6a6cb8da0..489fea3c0 100644
--- a/lib/phoenix/endpoint.ex
+++ b/lib/phoenix/endpoint.ex
@@ -831,10 +831,8 @@ defmodule Phoenix.Endpoint do
   end
 
   @doc false
+  @deprecated "Phoenix.Endpoint.instrument/4 is deprecated and has no effect. Use :telemetry instead"
   defmacro instrument(_endpoint_or_conn_or_socket, _event, _runtime, _fun) do
-    IO.warn "Phoenix.Endpoint.instrument/4 is deprecated and has no effect. Use :telemetry instead",
-            Macro.Env.stacktrace(__CALLER__)
-
     :ok
   end
 
diff --git a/lib/phoenix/logger.ex b/lib/phoenix/logger.ex
index c8ac0bc9d..9f5ad8b57 100644
--- a/lib/phoenix/logger.ex
+++ b/lib/phoenix/logger.ex
@@ -11,15 +11,15 @@ defmodule Phoenix.Logger do
       endpoint at the beginning of every request.
       * Measurement: `%{time: System.monotonic_time}`
       * Metadata: `%{conn: Plug.Conn.t, options: Keyword.t}`
-      * Options: `%{log: Logger.level | false}`
-      * Disable logging: In your endpoint `plug Plug.Telemetry, ..., options: [log: false]`
+      * Options: `%{log: Logger.level}`
+      * Disable logging: Remove `plug Plug.Telemetry, ...` from your endpoint.ex
 
     * `[:phoenix, :endpoint, :stop]` - dispatched by `Plug.Telemetry` in your
       endpoint whenever the response is sent
       * Measurement: `%{duration: native_time}`
       * Metadata: `%{conn: Plug.Conn.t, options: Keyword.t}`
-      * Options: `%{log: Logger.level | false}`
-      * Disable logging: In your endpoint `plug Plug.Telemetry, ..., options: [log: false]`
+      * Options: `%{log: Logger.level}`
+      * Disable logging: Remove `plug Plug.Telemetry, ...` from your endpoint.ex
 
     * `[:phoenix, :router_dispatch, :start]` - dispatched by `Phoenix.Router`
       before dispatching to a matched route
diff --git a/lib/phoenix/socket.ex b/lib/phoenix/socket.ex
index a67fe353e..a5fff3d6a 100644
--- a/lib/phoenix/socket.ex
+++ b/lib/phoenix/socket.ex
@@ -13,12 +13,12 @@ defmodule Phoenix.Socket do
   By default, Phoenix supports both websockets and longpoll when invoking
   `Phoenix.Endpoint.socket/3` in your endpoint:
 
-      socket "/socket", MyApp.Socket, websocket: true, longpoll: false
+      socket "/socket", MyAppWeb.Socket, websocket: true, longpoll: false
 
   The command above means incoming socket connections can be made via
   a WebSocket connection. Events are routed by topic to channels:
 
-      channel "room:lobby", MyApp.LobbyChannel
+      channel "room:lobby", MyAppWeb.LobbyChannel
 
   See `Phoenix.Channel` for more information on channels.
 
@@ -36,10 +36,10 @@ defmodule Phoenix.Socket do
 
   ## Examples
 
-      defmodule MyApp.UserSocket do
+      defmodule MyAppWeb.UserSocket do
         use Phoenix.Socket
 
-        channel "room:*", MyApp.RoomChannel
+        channel "room:*", MyAppWeb.RoomChannel
 
         def connect(params, socket, _connect_info) do
           {:ok, assign(socket, :user_id, params["user_id"])}
@@ -49,7 +49,7 @@ defmodule Phoenix.Socket do
       end
 
       # Disconnect all user's socket connections and their multiplexed channels
-      MyApp.Endpoint.broadcast("users_socket:" <> user.id, "disconnect", %{})
+      MyAppWeb.Endpoint.broadcast("users_socket:" <> user.id, "disconnect", %{})
 
   ## Socket fields
 
@@ -57,8 +57,8 @@ defmodule Phoenix.Socket do
     * `:assigns` - The map of socket assigns, default: `%{}`
     * `:channel` - The current channel module
     * `:channel_pid` - The channel pid
-    * `:endpoint` - The endpoint module where this socket originated, for example: `MyApp.Endpoint`
-    * `:handler` - The socket module where this socket originated, for example: `MyApp.UserSocket`
+    * `:endpoint` - The endpoint module where this socket originated, for example: `MyAppWeb.Endpoint`
+    * `:handler` - The socket module where this socket originated, for example: `MyAppWeb.UserSocket`
     * `:joined` - If the socket has effectively joined the channel
     * `:join_ref` - The ref sent by the client when joining
     * `:ref` - The latest ref sent by the client
@@ -216,7 +216,7 @@ defmodule Phoenix.Socket do
   Would allow you to broadcast a `"disconnect"` event and terminate
   all active sockets and channels for a given user:
 
-      MyApp.Endpoint.broadcast("users_socket:" <> user.id, "disconnect", %{})
+      MyAppWeb.Endpoint.broadcast("users_socket:" <> user.id, "disconnect", %{})
 
   Returning `nil` makes this socket anonymous.
   """
@@ -328,7 +328,7 @@ defmodule Phoenix.Socket do
 
     * `topic_pattern` - The string pattern, for example `"room:*"`, `"users:*"`,
       or `"system"`
-    * `module` - The channel module handler, for example `MyApp.RoomChannel`
+    * `module` - The channel module handler, for example `MyAppWeb.RoomChannel`
     * `opts` - The optional list of options, see below
 
   ## Options
@@ -370,10 +370,9 @@ defmodule Phoenix.Socket do
   defp tear_alias(other), do: other
 
   @doc false
+  @deprecated "transport/3 in Phoenix.Socket is deprecated and has no effect"
   defmacro transport(_name, _module, _config \\ []) do
-    quote do
-      IO.warn "transport/3 in Phoenix.Socket is deprecated and has no effect"
-    end
+    :ok
   end
 
   defmacro __before_compile__(env) do
diff --git a/lib/phoenix/token.ex b/lib/phoenix/token.ex
index ff8705186..1ad231d96 100644
--- a/lib/phoenix/token.ex
+++ b/lib/phoenix/token.ex
@@ -15,8 +15,8 @@ defmodule Phoenix.Token do
   the id from a database. For example:
 
       iex> user_id = 1
-      iex> token = Phoenix.Token.sign(MyApp.Endpoint, "user salt", user_id)
-      iex> Phoenix.Token.verify(MyApp.Endpoint, "user salt", token, max_age: 86400)
+      iex> token = Phoenix.Token.sign(MyApp.Endpoint, "user auth", user_id)
+      iex> Phoenix.Token.verify(MyApp.Endpoint, "user auth", token, max_age: 86400)
       {:ok, 1}
 
   In that example we have a user's id, we generate a token and
@@ -38,8 +38,9 @@ defmodule Phoenix.Token do
 
   The second argument is a [cryptographic salt](https://en.wikipedia.org/wiki/Salt_(cryptography))
   which must be the same in both calls to `sign/4` and `verify/4`.
-  For instance, it may be called "user auth" when generating a token
-  that will be used to authenticate users on channels or on your APIs.
+  For instance, it may be called "user auth" and treated as namespace
+  when generating a token that will be used to authenticate users on
+  channels or on your APIs.
 
   The third argument can be any term (string, int, list, etc.)
   that you wish to codify into the token. Upon valid verification,
@@ -52,14 +53,14 @@ defmodule Phoenix.Token do
   One is via the meta tag:
 
       <%= tag :meta, name: "channel_token",
-                     content: Phoenix.Token.sign(@conn, "user salt", @current_user.id) %>
+                     content: Phoenix.Token.sign(@conn, "user auth", @current_user.id) %>
 
   Or an endpoint that returns it:
 
       def create(conn, params) do
         user = User.create(params)
         render(conn, "user.json",
-               %{token: Phoenix.Token.sign(conn, "user salt", user.id), user: user})
+               %{token: Phoenix.Token.sign(conn, "user auth", user.id), user: user})
       end
 
   Once the token is sent, the client may now send it back to the server
@@ -70,7 +71,7 @@ defmodule Phoenix.Token do
         use Phoenix.Socket
 
         def connect(%{"token" => token}, socket, _connect_info) do
-          case Phoenix.Token.verify(socket, "user salt", token, max_age: 86400) do
+          case Phoenix.Token.verify(socket, "user auth", token, max_age: 86400) do
             {:ok, user_id} ->
               socket = assign(socket, :user, Repo.get!(User, user_id))
               {:ok, socket}
@@ -145,8 +146,8 @@ defmodule Phoenix.Token do
 
       iex> user_id    = 99
       iex> secret     = "kjoy3o1zeidquwy1398juxzldjlksahdk3"
-      iex> user_salt  = "user salt"
-      iex> token      = Phoenix.Token.sign(secret, user_salt, user_id)
+      iex> namespace  = "user auth"
+      iex> token      = Phoenix.Token.sign(secret, namespace, user_id)
 
   The mechanism for passing the token to the client is typically through a
   cookie, a JSON response body, or HTTP header. For now, assume the client has
@@ -155,7 +156,7 @@ defmodule Phoenix.Token do
   When the server receives a request, it can use `verify/4` to determine if it
   should provide the requested resources to the client:
 
-      iex> Phoenix.Token.verify(secret, user_salt, token, max_age: 86400)
+      iex> Phoenix.Token.verify(secret, namespace, token, max_age: 86400)
       {:ok, 99}
 
   In this example, we know the client sent a valid token because `verify/4`
@@ -165,10 +166,10 @@ defmodule Phoenix.Token do
   However, if the client had sent an expired or otherwise invalid token
   `verify/4` would have returned an error instead:
 
-      iex> Phoenix.Token.verify(secret, user_salt, expired, max_age: 86400)
+      iex> Phoenix.Token.verify(secret, namespace, expired, max_age: 86400)
       {:error, :expired}
 
-      iex> Phoenix.Token.verify(secret, user_salt, invalid, max_age: 86400)
+      iex> Phoenix.Token.verify(secret, namespace, invalid, max_age: 86400)
       {:error, :invalid}
 
   ## Options
diff --git a/priv/templates/phx.gen.live/form.html.leex b/priv/templates/phx.gen.live/form.html.leex
index d7f827f3f..18b819e03 100644
--- a/priv/templates/phx.gen.live/form.html.leex
+++ b/priv/templates/phx.gen.live/form.html.leex
@@ -1,8 +1,7 @@
 <h2><%%= @title %></h2>
 
 <%%= f = form_for @changeset, "#",
-  id: "form-#{@id}",
-  phx_target: "#form-#{@id}",
+  phx_target: @myself,
   phx_change: "validate",
   phx_submit: "save" %>
 <%= for {label, input, error} <- inputs, input do %>
diff --git a/priv/templates/phx.gen.live/index.ex b/priv/templates/phx.gen.live/index.ex
index d6f65356d..abdae671b 100644
--- a/priv/templates/phx.gen.live/index.ex
+++ b/priv/templates/phx.gen.live/index.ex
@@ -5,32 +5,29 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
   alias <%= inspect schema.module %>
 
   def mount(_params, _session, socket) do
-    {:ok, socket}
+    {:ok, assign(socket, :<%= schema.plural %>, fetch_<%= schema.plural %>())}
   end
 
   def handle_params(params, _url, socket) do
-    {:noreply, handle_action(socket.assigns.live_action, params, socket)}
+    {:noreply, apply_action(socket, socket.assigns.live_action, params)}
   end
 
-  defp handle_action(:edit, %{"id" => id}, socket) do
+  defp apply_action(socket, :edit, %{"id" => id}) do
     socket
     |> assign(:page_title, "Edit <%= schema.human_singular %>")
     |> assign(:<%= schema.singular %>, <%= inspect context.alias %>.get_<%= schema.singular %>!(id))
-    |> assign_new(:<%= schema.plural %>, &fetch_<%= schema.plural %>/0)
   end
 
-  defp handle_action(:new, _params, socket) do
+  defp apply_action(socket, :new, _params) do
     socket
     |> assign(:page_title, "New <%= schema.human_singular %>")
     |> assign(:<%= schema.singular %>, %<%= inspect schema.alias %>{})
-    |> assign_new(:<%= schema.plural %>, &fetch_<%= schema.plural %>/0)
   end
 
-  defp handle_action(:index, _params, socket) do
+  defp apply_action(socket, :index, _params) do
     socket
     |> assign(:page_title, "Listing <%= schema.human_plural %>")
     |> assign(:<%= schema.singular %>, nil)
-    |> assign(:<%= schema.plural %>, fetch_<%= schema.plural %>())
   end
 
   def handle_event("delete", %{"id" => id}, socket) do
diff --git a/priv/templates/phx.gen.live/index.html.leex b/priv/templates/phx.gen.live/index.html.leex
index b209b4821..0c76852ca 100644
--- a/priv/templates/phx.gen.live/index.html.leex
+++ b/priv/templates/phx.gen.live/index.html.leex
@@ -17,9 +17,9 @@
       <th></th>
     </tr>
   </thead>
-  <tbody>
+  <tbody id="<%= schema.plural %>">
     <%%= for <%= schema.singular %> <- @<%= schema.plural %> do %>
-      <tr>
+      <tr id="<%= schema.singular %>-<%%= <%= schema.singular %>.id %>">
 <%= for {k, _} <- schema.attrs do %>        <td><%%= <%= schema.singular %>.<%= k %> %></td>
 <% end %>
         <td>
diff --git a/priv/templates/phx.gen.live/show.html.leex b/priv/templates/phx.gen.live/show.html.leex
index 254adef73..172b30e0c 100644
--- a/priv/templates/phx.gen.live/show.html.leex
+++ b/priv/templates/phx.gen.live/show.html.leex
@@ -18,5 +18,5 @@
 <% end %>
 </ul>
 
-<span><%%= live_patch "Edit", to: Routes.<%= schema.singular %>_show_path(@socket, :edit, @<%= schema.singular %>), class: "button", phx_disable_with: "loading..." %></span>
+<span><%%= live_patch "Edit", to: Routes.<%= schema.singular %>_show_path(@socket, :edit, @<%= schema.singular %>), class: "button" %></span>
 <span><%%= live_redirect "Back", to: Routes.<%= schema.singular %>_index_path(@socket, :index) %></span>


Test patch:
diff --git a/installer/templates/phx_test/live/page_live_test.exs b/installer/templates/phx_test/live/page_live_test.exs
index 08df863c7..75cf111d4 100644
--- a/installer/templates/phx_test/live/page_live_test.exs
+++ b/installer/templates/phx_test/live/page_live_test.exs
@@ -4,8 +4,8 @@ defmodule <%= web_namespace %>.PageLiveTest do
   import Phoenix.LiveViewTest
 
   test "disconnected and connected render", %{conn: conn} do
-    {:ok, page_live, disconneted_html} = live(conn, "/")
-    assert disconneted_html =~ "Welcome to Phoenix!"
+    {:ok, page_live, disconnected_html} = live(conn, "/")
+    assert disconnected_html =~ "Welcome to Phoenix!"
     assert render(page_live) =~ "Welcome to Phoenix!"
   end
 end
diff --git a/lib/phoenix/test/channel_test.ex b/lib/phoenix/test/channel_test.ex
index 042e27e60..6875928f1 100644
--- a/lib/phoenix/test/channel_test.ex
+++ b/lib/phoenix/test/channel_test.ex
@@ -241,14 +241,14 @@ defmodule Phoenix.ChannelTest do
   end
 
   @doc false
+  @deprecated "Phoenix.ChannelTest.socket/0 is deprecated, please call socket/1 instead"
   defmacro socket() do
-    IO.warn "Phoenix.ChannelTest.socket/0 is deprecated, please call socket/1 instead"
     build_socket(nil, nil, [], __CALLER__)
   end
 
   @doc false
+  @deprecated "Phoenix.ChannelTest.socket/2 is deprecated, please call socket/3 instead"
   defmacro socket(id, assigns) do
-    IO.warn "Phoenix.ChannelTest.socket/2 is deprecated, please call socket/3 instead"
     build_socket(nil, id, assigns, __CALLER__)
   end
 
diff --git a/test/mix/tasks/phx_test.exs b/test/mix/tasks/phx_test.exs
index 399aae542..8829b70e0 100644
--- a/test/mix/tasks/phx_test.exs
+++ b/test/mix/tasks/phx_test.exs
@@ -11,6 +11,7 @@ defmodule Mix.Tasks.Phx.Test do
     assert_received {:mix_shell, :info, ["mix phx.gen.embedded" <> _]}
     assert_received {:mix_shell, :info, ["mix phx.gen.html" <> _]}
     assert_received {:mix_shell, :info, ["mix phx.gen.json" <> _]}
+    assert_received {:mix_shell, :info, ["mix phx.gen.live" <> _]}
   end
 
   test "expects no arguments" do