Repository: phoenixframework/phoenix
Pull request #3290 (2019-02-24 05:36:38)

Update project tagline to be more clear
This is a super nitpick, but [my friend](https://github.com/jalcine) dared me to open a PR, so here it is.

The project tagline currently reads:

> A productive web framework that does not compromise speed and maintainability.

While this may technically be true, it translates to the following logic:

```
(doesCompromiseSpeed && doesCompromiseMaintainability) === false
```

The issue with this is that since only one of the conditions needs to be `false`, it could be interpreted along the lines of:

> Other frameworks compromise both speed and maintainability, but Phoenix only compromises one of them.

Thus, I think it'd be better to change the "and" to an "or," so that it's clear that Phoenix does not compromise either speed _or_ maintainability. In other words:

```
(doesCompromiseSpeed || doesCompromiseMaintainability) === false
```


Patch:
diff --git a/README.md b/README.md
index ac62e3383..b572f66b9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 ![phoenix logo](https://raw.githubusercontent.com/phoenixframework/phoenix/master/priv/static/phoenix.png)
 > ### Productive. Reliable. Fast.
-> A productive web framework that does not compromise speed and maintainability.
+> A productive web framework that does not compromise speed or maintainability.
 
 [![Build Status](https://api.travis-ci.org/phoenixframework/phoenix.svg?branch=master)](https://travis-ci.org/phoenixframework/phoenix)
 [![Inline docs](http://inch-ci.org/github/phoenixframework/phoenix.svg)](http://inch-ci.org/github/phoenixframework/phoenix)
diff --git a/assets/js/phoenix.js b/assets/js/phoenix.js
index 295e8cbe4..2bc742947 100644
--- a/assets/js/phoenix.js
+++ b/assets/js/phoenix.js
@@ -773,6 +773,9 @@ export class Socket {
   /**
    *
    * @param {Object} params - The params to send when connecting, for example `{user_id: userToken}`
+   *
+   * Passing params to connect is deprecated; pass them in the Socket constructor instead:
+   * `new Socket("/socket", {params: {user_id: userToken}})`.
    */
   connect(params){
     if(params){
@@ -847,7 +850,7 @@ export class Socket {
    * @private
    */
 
-  resetHeartbeat(){ if(this.conn.skipHeartbeat){ return }
+  resetHeartbeat(){ if(this.conn && this.conn.skipHeartbeat){ return }
     this.pendingHeartbeatRef = null
     clearInterval(this.heartbeatTimer)
     this.heartbeatTimer = setInterval(() => this.sendHeartbeat(), this.heartbeatIntervalMs)
diff --git a/guides/channels.md b/guides/channels.md
index aaada208a..e0dfe06d4 100644
--- a/guides/channels.md
+++ b/guides/channels.md
@@ -54,7 +54,7 @@ Once the connection is established, each incoming message from a client is route
 If the channel server asks to broadcast a message, that message is sent to the local PubSub, which sends it out to any clients connected to the same server and subscribed to that topic.
 
 If there are other nodes in the cluster, the local PubSub also forwards the message to their PubSubs, which send it out to their own subscribers.
-Because only one message has to be sent per additional node, the performance cost of adding nodes in negligible, while each new node supports many more subscribers.
+Because only one message has to be sent per additional node, the performance cost of adding nodes is negligible, while each new node supports many more subscribers.
 
 The message flow looks something like this:
 
diff --git a/guides/deployment/deployment.md b/guides/deployment/deployment.md
index 668f6ac46..aa6d417d7 100644
--- a/guides/deployment/deployment.md
+++ b/guides/deployment/deployment.md
@@ -65,7 +65,7 @@ This step is required only if you have static assets like images, JavaScript, st
 Compilation of static assets happens in two steps:
 
 ```console
-$ cd assets && webpack --mode production
+$ npm run deploy --prefix ./assets
 
 $ mix phx.digest
 
@@ -122,7 +122,7 @@ $ mix deps.get --only prod
 $ MIX_ENV=prod mix compile
 
 # Compile assets
-$ cd assets && webpack --mode production && cd ..
+$ npm run deploy --prefix ./assets
 
 $ mix phx.digest
 
diff --git a/guides/deployment/heroku.md b/guides/deployment/heroku.md
index ad30c3dd4..5ef88cfac 100644
--- a/guides/deployment/heroku.md
+++ b/guides/deployment/heroku.md
@@ -146,7 +146,7 @@ First, let's make sure our secret key is loaded from Heroku's environment variab
 config :hello, HelloWeb.Endpoint,
   url: [host: "example.com", port: 80],
   cache_static_manifest: "priv/static/cache_manifest.json",
-  secret_key_base: System.get_env("SECRET_KEY_BASE") || raise "missing SECRET_KEY_BASE env var"
+  secret_key_base: System.get_env("SECRET_KEY_BASE") || raise("missing SECRET_KEY_BASE env var")
 ```
 
 Then, we'll add the production database configuration to `config/prod.exs`:
diff --git a/guides/presence.md b/guides/presence.md
index f3bb602f9..4569107fe 100644
--- a/guides/presence.md
+++ b/guides/presence.md
@@ -97,7 +97,7 @@ end
 
 Finally we can use the client-side Presence library included in `phoenix.js` to manage the state and presence diffs that come down the socket. It listens for the `"presence_state"` and `"presence_diff"` events and provides a simple callback for you to handle the events as they happen, with the `onSync` callback.
 
-The `onSync` callback allows you to easily react to presence state changes, which most often results in re-rendering an updated list of active users. You can use the `list` method is to format and return each individual presence based on the needs of your application.
+The `onSync` callback allows you to easily react to presence state changes, which most often results in re-rendering an updated list of active users. You can use the `list` method to format and return each individual presence based on the needs of your application.
 
 To iterate users, we use the `presences.list()` function which accepts a callback. The callback will be called for each presence item with 2 arguments, the presence id and a list of metas (one for each presence for that presence id). We use this to display the users and the number of devices they are online with.
 
diff --git a/guides/routing.md b/guides/routing.md
index 79edd7107..e4a62cbc7 100644
--- a/guides/routing.md
+++ b/guides/routing.md
@@ -32,7 +32,7 @@ defmodule HelloWeb.Router do
   # end
 end
 ```
-The name you gave your application will appear instead of `Hello` for both the router module and controller name.
+The name you gave your application will appear instead of `HelloWeb` for both the router module and controller name.
 
 The first line of this module, `use HelloWeb, :router`, simply makes Phoenix router functions available in our particular router.
 
@@ -115,7 +115,7 @@ user_path  PATCH   /users/:id       HelloWeb.UserController :update
 user_path  DELETE  /users/:id       HelloWeb.UserController :delete
 ```
 
-Of course, the name of your project will replace `Hello`.
+Of course, the name of your project will replace `HelloWeb`.
 
 This is the standard matrix of HTTP verbs, paths, and controller actions. Let's look at them individually, in a slightly different order.
 
diff --git a/guides/views.md b/guides/views.md
index 3c0bd6e5d..787341c70 100644
--- a/guides/views.md
+++ b/guides/views.md
@@ -75,7 +75,7 @@ Let's open up the `lib/hello_web/templates/page/index.html.eex` and locate this
 ```html
 <section class="phx-hero">
   <h1><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
-  <p>A productive web framework that<br/>does not compromise speed and maintainability.</p>
+  <p>A productive web framework that<br/>does not compromise speed or maintainability.</p>
 </section>
 ```
 
@@ -84,7 +84,7 @@ Then let's add a line with a link back to the same page. (The objective is to se
 ```html
 <section class="phx-hero">
   <h1><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
-  <p>A productive web framework that<br/>does not compromise speed and maintainability.</p>
+  <p>A productive web framework that<br/>does not compromise speed or maintainability.</p>
   <p><a href="<%= Routes.page_path(@conn, :index) %>">Link back to this page</a></p>
 </section>
 ```
diff --git a/installer/templates/phx_assets/webpack/webpack.config.js b/installer/templates/phx_assets/webpack/webpack.config.js
index d63d8e799..40b8fa684 100644
--- a/installer/templates/phx_assets/webpack/webpack.config.js
+++ b/installer/templates/phx_assets/webpack/webpack.config.js
@@ -13,7 +13,7 @@ module.exports = (env, options) => ({
     ]
   },
   entry: {
-      './js/app.js': ['./js/app.js'].concat(glob.sync('./vendor/**/*.js'))
+    './js/app.js': ['./js/app.js'].concat(glob.sync('./vendor/**/*.js'))
   },
   output: {
     filename: 'app.js',
diff --git a/installer/templates/phx_single/config/prod.exs b/installer/templates/phx_single/config/prod.exs
index 375acea39..d767c2675 100644
--- a/installer/templates/phx_single/config/prod.exs
+++ b/installer/templates/phx_single/config/prod.exs
@@ -22,7 +22,7 @@ config :logger, level: :info
 # To get SSL working, you will need to add the `https` key
 # to the previous section and set your `:url` port to 443:
 #
-#     config :<%= app_name %>, <%= endpoint_module %>,
+#     config :<%= web_app_name %>, <%= endpoint_module %>,
 #       ...
 #       url: [host: "example.com", port: 443],
 #       https: [
@@ -46,7 +46,7 @@ config :logger, level: :info
 # We also recommend setting `force_ssl` in your endpoint, ensuring
 # no data is ever sent via http, always redirecting to https:
 #
-#     config :<%= app_name %>, <%= endpoint_module %>,
+#     config :<%= web_app_name %>, <%= endpoint_module %>,
 #       force_ssl: [hsts: true]
 #
 # Check `Plug.SSL` for all available options in `force_ssl`.
@@ -61,7 +61,7 @@ config :logger, level: :info
 # Alternatively, you can configure exactly which server to
 # start per endpoint:
 #
-#     config :<%= app_name %>, <%= endpoint_module %>, server: true
+#     config :<%= web_app_name %>, <%= endpoint_module %>, server: true
 #
 # Note you can't rely on `System.get_env/1` when using releases.
 # See the releases documentation accordingly.
diff --git a/installer/templates/phx_umbrella/apps/app_name_web/config/prod.exs b/installer/templates/phx_umbrella/apps/app_name_web/config/prod.exs
index 2c32b6807..67688df68 100644
--- a/installer/templates/phx_umbrella/apps/app_name_web/config/prod.exs
+++ b/installer/templates/phx_umbrella/apps/app_name_web/config/prod.exs
@@ -23,7 +23,7 @@ config :<%= web_app_name %>, <%= endpoint_module %>,
 # To get SSL working, you will need to add the `https` key
 # to the previous section and set your `:url` port to 443:
 #
-#     config :<%= app_name %>, <%= endpoint_module %>,
+#     config :<%= web_app_name %>, <%= endpoint_module %>,
 #       ...
 #       url: [host: "example.com", port: 443],
 #       https: [
@@ -47,7 +47,7 @@ config :<%= web_app_name %>, <%= endpoint_module %>,
 # We also recommend setting `force_ssl` in your endpoint, ensuring
 # no data is ever sent via http, always redirecting to https:
 #
-#     config :<%= app_name %>, <%= endpoint_module %>,
+#     config :<%= web_app_name %>, <%= endpoint_module %>,
 #       force_ssl: [hsts: true]
 #
 # Check `Plug.SSL` for all available options in `force_ssl`.
@@ -62,7 +62,7 @@ config :<%= web_app_name %>, <%= endpoint_module %>,
 # Alternatively, you can configure exactly which server to
 # start per endpoint:
 #
-#     config :<%= app_name %>, <%= endpoint_module %>, server: true
+#     config :<%= web_app_name %>, <%= endpoint_module %>, server: true
 #
 # Note you can't rely on `System.get_env/1` when using releases.
 # See the releases documentation accordingly.
diff --git a/installer/templates/phx_web/templates/page/index.html.eex b/installer/templates/phx_web/templates/page/index.html.eex
index 9953a4584..07a2ae6bd 100644
--- a/installer/templates/phx_web/templates/page/index.html.eex
+++ b/installer/templates/phx_web/templates/page/index.html.eex
@@ -1,6 +1,6 @@
 <section class="phx-hero">
   <h1><%%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
-  <p>A productive web framework that<br/>does not compromise speed and maintainability.</p>
+  <p>A productive web framework that<br/>does not compromise speed or maintainability.</p>
 </section>
 
 <section class="row">
diff --git a/lib/mix/phoenix.ex b/lib/mix/phoenix.ex
index 5a8464f9f..c65691402 100644
--- a/lib/mix/phoenix.ex
+++ b/lib/mix/phoenix.ex
@@ -91,7 +91,7 @@ defmodule Mix.Phoenix do
 
   """
   def inflect(singular) do
-    base       = Mix.Phoenix.base
+    base       = Mix.Phoenix.base()
     web_module = base |> web_module() |> inspect()
     scoped     = Phoenix.Naming.camelize(singular)
     path       = Phoenix.Naming.underscore(scoped)
diff --git a/lib/mix/tasks/phx.ex b/lib/mix/tasks/phx.ex
index 2e6cef7d7..9ddf6a90d 100644
--- a/lib/mix/tasks/phx.ex
+++ b/lib/mix/tasks/phx.ex
@@ -22,7 +22,7 @@ defmodule Mix.Tasks.Phx do
     Application.ensure_all_started(:phoenix)
     Mix.shell.info "Phoenix v#{Application.spec(:phoenix, :vsn)}"
     Mix.shell.info "Productive. Reliable. Fast."
-    Mix.shell.info "A productive web framework that does not compromise speed and maintainability."
+    Mix.shell.info "A productive web framework that does not compromise speed or maintainability."
     Mix.shell.info "\nAvailable tasks:\n"
     Mix.Tasks.Help.run(["--search", "phx."])
   end
diff --git a/lib/mix/tasks/phx.gen.context.ex b/lib/mix/tasks/phx.gen.context.ex
index b257cd45b..8b9a1ea8c 100644
--- a/lib/mix/tasks/phx.gen.context.ex
+++ b/lib/mix/tasks/phx.gen.context.ex
@@ -208,6 +208,10 @@ defmodule Mix.Tasks.Phx.Gen.Context do
         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"
+      context == Mix.Phoenix.base() ->
+        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"
       true ->
         args
     end
diff --git a/lib/phoenix/channel/server.ex b/lib/phoenix/channel/server.ex
index bc3542f5c..6082d2882 100644
--- a/lib/phoenix/channel/server.ex
+++ b/lib/phoenix/channel/server.ex
@@ -38,10 +38,23 @@ defmodule Phoenix.Channel.Server do
     args = [channel, {payload, from, socket}]
 
     case PoolSupervisor.start_child(socket.endpoint, socket.handler, from, args) do
-      {:ok, :undefined} ->
-        receive do: ({^ref, reply} -> {:error, reply})
       {:ok, pid} ->
-        receive do: ({^ref, reply} -> {:ok, reply, pid})
+        mon_ref = Process.monitor(pid)
+
+        receive do
+          {^ref, {:ok, reply}} ->
+            Process.demonitor(mon_ref, [:flush])
+            {:ok, reply, pid}
+
+          {^ref, {:error, reply}} ->
+            Process.demonitor(mon_ref, [:flush])
+            {:error, reply}
+
+          {:DOWN, ^mon_ref, _, _, reason} ->
+            Logger.error fn -> Exception.format_exit(reason) end
+            {:error, %{reason: "join crashed"}}
+        end
+
       {:error, reason} ->
         Logger.error fn -> Exception.format_exit(reason) end
         {:error, %{reason: "join crashed"}}
@@ -194,6 +207,23 @@ defmodule Phoenix.Channel.Server do
 
   @doc false
   def init({auth_payload, from, socket}) do
+    # TODO: Use handle_continue when we support Erlang/OTP 21+.
+    send(self(), {:join, __MODULE__})
+    {:ok, {auth_payload, from, socket}}
+  end
+
+  @doc false
+  def handle_call(:socket, _from, socket) do
+    {:reply, socket, socket}
+  end
+
+  @doc false
+  def handle_cast(:close, socket) do
+    {:stop, {:shutdown, :closed}, socket}
+  end
+
+  @doc false
+  def handle_info({:join, __MODULE__}, {auth_payload, from, socket}) do
     %{channel: channel, topic: topic, private: private} = socket
 
     socket = %{socket
@@ -202,13 +232,13 @@ defmodule Phoenix.Channel.Server do
 
     case channel_join(socket, channel, topic, auth_payload) do
       {:ok, socket} ->
-        init(socket, channel, topic, %{}, from)
+        init_info(socket, channel, topic, %{}, from)
       {:ok, reply, socket} ->
-        init(socket, channel, topic, reply, from)
+        init_info(socket, channel, topic, reply, from)
       {:error, reply} ->
         log_join socket, topic, fn -> "Replied #{topic} :error" end
-        GenServer.reply(from, reply)
-        :ignore
+        GenServer.reply(from, {:error, reply})
+        {:stop, :shutdown, socket}
       other ->
         raise """
         channel #{inspect socket.channel}.join/3 is expected to return one of:
@@ -222,40 +252,6 @@ defmodule Phoenix.Channel.Server do
     end
   end
 
-  defp channel_join(socket, channel, topic, auth_payload) do
-    instrument = %{params: auth_payload, socket: socket}
-
-    Phoenix.Endpoint.instrument socket, :phoenix_channel_join, instrument, fn ->
-      channel.join(topic, auth_payload, socket)
-    end
-  end
-
-  defp init(socket, channel, topic, reply, from) do
-    %{transport_pid: transport_pid, serializer: serializer, pubsub_server: pubsub_server} = socket
-    Process.monitor(transport_pid)
-
-    fastlane = {transport_pid, serializer, channel.__intercepts__()}
-    PubSub.subscribe(pubsub_server, topic, link: true, fastlane: fastlane)
-
-    log_join socket, topic, fn -> "Replied #{topic} :ok" end
-    GenServer.reply(from, reply)
-    {:ok, %{socket | joined: true}}
-  end
-
-  defp log_join(%{private: %{log_join: false}}, _topic, _func), do: :noop
-  defp log_join(%{private: %{log_join: level}}, _topic, func), do: Logger.log(level, func)
-
-  @doc false
-  def handle_call(:socket, _from, socket) do
-    {:reply, socket, socket}
-  end
-
-  @doc false
-  def handle_cast(:close, socket) do
-    {:stop, {:shutdown, :closed}, socket}
-  end
-
-  @doc false
   def handle_info(%Message{topic: topic, event: "phx_leave", ref: ref}, %{topic: topic} = socket) do
     handle_in({:stop, {:shutdown, :left}, :ok, put_in(socket.ref, ref)})
   end
@@ -318,6 +314,10 @@ defmodule Phoenix.Channel.Server do
     end
   end
 
+  def terminate(_reason, _socket) do
+    :ok
+  end
+
   @doc false
   def fastlane(subscribers, from, %Broadcast{event: event} = msg) do
     Enum.reduce(subscribers, %{}, fn
@@ -353,6 +353,31 @@ defmodule Phoenix.Channel.Server do
     end)
   end
 
+  ## Joins
+
+  defp channel_join(socket, channel, topic, auth_payload) do
+    instrument = %{params: auth_payload, socket: socket}
+
+    Phoenix.Endpoint.instrument socket, :phoenix_channel_join, instrument, fn ->
+      channel.join(topic, auth_payload, socket)
+    end
+  end
+
+  defp init_info(socket, channel, topic, reply, from) do
+    %{transport_pid: transport_pid, serializer: serializer, pubsub_server: pubsub_server} = socket
+    Process.monitor(transport_pid)
+
+    fastlane = {transport_pid, serializer, channel.__intercepts__()}
+    PubSub.subscribe(pubsub_server, topic, link: true, fastlane: fastlane)
+
+    log_join socket, topic, fn -> "Replied #{topic} :ok" end
+    GenServer.reply(from, {:ok, reply})
+    {:noreply, %{socket | joined: true}}
+  end
+
+  defp log_join(%{private: %{log_join: false}}, _topic, _func), do: :noop
+  defp log_join(%{private: %{log_join: level}}, _topic, func), do: Logger.log(level, func)
+
   ## Handle results
 
   defp handle_result({:stop, reason, socket}, _callback) do
diff --git a/lib/phoenix/controller.ex b/lib/phoenix/controller.ex
index 90d71add9..3e6ea6d6c 100644
--- a/lib/phoenix/controller.ex
+++ b/lib/phoenix/controller.ex
@@ -806,7 +806,7 @@ defmodule Phoenix.Controller do
   end
 
   @doc """
-  Puts the URL or `%URI{}` to be used for route generation.
+  Puts the url string or `%URI{}` to be used for route generation.
 
   This function overrides the default URL generation pulled
   from the `%Plug.Conn{}`'s endpoint configuration.
@@ -824,8 +824,8 @@ defmodule Phoenix.Controller do
 
   Now when you call `Routes.some_route_url(conn, ...)`, it will use
   the router url set above. Keep in mind that, if you want to generate
-  routes to the current domain, it is preferred to use `Routes.some_route_path`
-  helpers, as those are always relative.
+  routes to the *current* domain, it is preferred to use
+  `Routes.some_route_path` helpers, as those are always relative.
   """
   def put_router_url(conn, %URI{} = uri) do
     put_private(conn, :phoenix_router_url, uri)
@@ -837,12 +837,22 @@ defmodule Phoenix.Controller do
   @doc """
   Puts the format in the connection.
 
+  This format is used when rendering a template as an atom.
+  For example, `render(conn, :foo)` will render `"foo.FORMAT"`
+  where the format is the one set here. The default format
+  is typically set from the negotiation done in `accepts/2`.
+
   See `get_format/1` for retrieval.
   """
   def put_format(conn, format), do: put_private(conn, :phoenix_format, format)
 
   @doc """
   Returns the request format, such as "json", "html".
+
+  This format is used when rendering a template as an atom.
+  For example, `render(conn, :foo)` will render `"foo.FORMAT"`
+  where the format is the one set here. The default format
+  is typically set from the negotiation done in `accepts/2`.
   """
   def get_format(conn) do
     conn.private[:phoenix_format] || conn.params["_format"]
@@ -1344,12 +1354,26 @@ defmodule Phoenix.Controller do
   end
 
   @doc """
-  Returns the current request path, with and without query params.
+  Returns the current request path with its default query parameters:
+
+      iex> current_path(conn)
+      "/users/123?existing=param"
+
+  See `current_path/2` to override the default parameters.
+  """
+  def current_path(%Plug.Conn{query_string: ""} = conn) do
+    conn.request_path
+  end
+
+  def current_path(%Plug.Conn{query_string: query_string} = conn) do
+    conn.request_path <> "?" <> query_string
+  end
+
+  @doc """
+  Returns the current path with the given query parameters.
 
-  By default, the connection's query params are included in
-  the generated path. Custom query params may be used instead
-  by providing a map of your own params. You may also retrieve
-  only the request path by passing an empty map of params.
+  You may also retrieve only the request path by passing an
+  empty map of params.
 
   ## Examples
 
@@ -1366,12 +1390,6 @@ defmodule Phoenix.Controller do
       "/users/123"
 
   """
-  def current_path(%Plug.Conn{query_string: ""} = conn) do
-    conn.request_path
-  end
-  def current_path(%Plug.Conn{query_string: query_string} = conn) do
-    conn.request_path <> "?" <> query_string
-  end
   def current_path(%Plug.Conn{} = conn, params) when params == %{} do
     conn.request_path
   end
@@ -1379,8 +1397,20 @@ defmodule Phoenix.Controller do
     conn.request_path <> "?" <> Plug.Conn.Query.encode(params)
   end
 
+  @doc """
+  Returns the current request url with its default query parameters:
+
+      iex> current_url(conn)
+      "https://www.example.com/users/123?existing=param"
+
+  See `current_url/2` to override the default parameters.
+  """
+  def current_url(%Plug.Conn{} = conn) do
+    Phoenix.Router.Helpers.url(router_module(conn), conn) <> current_path(conn)
+  end
+
   @doc ~S"""
-  Returns the current request URL, with and without query params.
+  Returns the current request URL with query params.
 
   The path will be retrieved from the currently requested path via
   `current_path/1`. The scheme, host and others will be received from
@@ -1420,11 +1450,8 @@ defmodule Phoenix.Controller do
       end
 
   However, if you want all generated URLs to always have a certain schema,
-  host, etc, you may invoke `put_router_url/2`.
+  host, etc, you may use `put_router_url/2`.
   """
-  def current_url(%Plug.Conn{} = conn) do
-    Phoenix.Router.Helpers.url(router_module(conn), conn) <> current_path(conn)
-  end
   def current_url(%Plug.Conn{} = conn, %{} = params) do
     Phoenix.Router.Helpers.url(router_module(conn), conn) <> current_path(conn, params)
   end
diff --git a/lib/phoenix/endpoint.ex b/lib/phoenix/endpoint.ex
index af6b93e4e..c4030ce47 100644
--- a/lib/phoenix/endpoint.ex
+++ b/lib/phoenix/endpoint.ex
@@ -562,7 +562,7 @@ defmodule Phoenix.Endpoint do
 
   defp plug() do
     quote location: :keep do
-      use Plug.Builder
+      use Plug.Builder, init_mode: Phoenix.plug_init_mode()
       import Phoenix.Endpoint
 
       Module.register_attribute(__MODULE__, :phoenix_sockets, accumulate: true)
@@ -789,6 +789,7 @@ defmodule Phoenix.Endpoint do
 
   defp socket_path(path, config) do
     end_path_fragment = Keyword.fetch!(config, :path)
+
     {vars, path} =
       String.split(path <> "/" <> end_path_fragment, "/", trim: true)
       |> Enum.join("/")
@@ -834,9 +835,10 @@ defmodule Phoenix.Endpoint do
       of options. See "Shared configuration" and
       "Longpoll configuration" for the whole list
 
-    * `:shutdown` - the maximum shutdown time of each channel
-      when the endpoint is shutting down. Applies only to
-      channel-based sockets
+  If your socket is implemented using `Phoenix.Socket`,
+  you can also pass here all options accepted on
+  `use Phoenix.Socket`. An option given here will override
+  the value in `Phoenix.Socket`.
 
   ## Examples
 
@@ -911,7 +913,6 @@ defmodule Phoenix.Endpoint do
               connect_info: [:uri, signing_salt: "NZIguRPO"]
             ]
 
-
   ## Websocket configuration
 
   The following configuration applies only to `:websocket`.
diff --git a/lib/phoenix/router.ex b/lib/phoenix/router.ex
index af260cd73..fdecd0b93 100644
--- a/lib/phoenix/router.ex
+++ b/lib/phoenix/router.ex
@@ -323,6 +323,13 @@ defmodule Phoenix.Router do
     Helpers.define(env, routes_with_exprs)
     {matches, _} = Enum.map_reduce(routes_with_exprs, %{}, &build_match/2)
 
+    checks =
+      for {%{line: line}, %{dispatch: {plug, _}}} <- routes_with_exprs, into: %{} do
+        quote line: line do
+          {unquote(plug).init([]), true}
+        end
+      end
+
     # @anno is used here to avoid warnings if forwarding to root path
     match_404 =
       quote @anno do
@@ -335,6 +342,9 @@ defmodule Phoenix.Router do
       @doc false
       def __routes__,  do: unquote(Macro.escape(routes))
 
+      @doc false
+      def __checks__, do: unquote({:__block__, [], Map.keys(checks)})
+
       @doc false
       def __helpers__, do: __MODULE__.Helpers
 
@@ -361,7 +371,6 @@ defmodule Phoenix.Router do
       host: host
     } = exprs
 
-
     {pipe_name, pipe_definition, known_pipelines} =
       case known_pipelines do
         %{^pipe_through => name} ->
@@ -671,7 +680,9 @@ defmodule Phoenix.Router do
 
     * `:path` - a string containing the path scope
     * `:as` - a string or atom containing the named helper scope
-    * `:alias` - an alias (atom) containing the controller scope
+    * `:alias` - an alias (atom) containing the controller scope.
+      When set, this value may be overridden per route by passing `alias: false`
+      to route definitions, such as `get`, `post`, etc.
     * `:host` - a string containing the host scope, or prefix host scope,
       ie `"foo.bar.com"`, `"foo."`
     * `:private` - a map of private data to merge into the connection when a route matches
@@ -745,6 +756,22 @@ defmodule Phoenix.Router do
     end
   end
 
+  @doc """
+  Returns the full alias with the current scope's aliased prefix.
+
+  Useful for applying the same short-hand alias handling to
+  other values besides the second argument in route definitions.
+
+  ## Examples
+
+      scope "/", MyPrefix do
+        get "/", ProxyPlug, controller: scoped_alias(__MODULE__, MyController)
+      end
+  """
+  def scoped_alias(router_module, alias) do
+    Scope.expand_alias(router_module, alias)
+  end
+
   @doc """
   Forwards a request at the given path to a plug.
 
diff --git a/lib/phoenix/router/scope.ex b/lib/phoenix/router/scope.ex
index 32ca4000f..9e8af044a 100644
--- a/lib/phoenix/router/scope.ex
+++ b/lib/phoenix/router/scope.ex
@@ -4,14 +4,16 @@ defmodule Phoenix.Router.Scope do
 
   @stack :phoenix_router_scopes
   @pipes :phoenix_pipeline_scopes
+  @top :phoenix_top_scopes
 
-  defstruct path: nil, alias: nil, as: nil, pipes: [], host: nil, private: %{}, assigns: %{}
+  defstruct path: [], alias: [], as: [], pipes: [], host: nil, private: %{}, assigns: %{}
 
   @doc """
   Initializes the scope.
   """
   def init(module) do
-    Module.put_attribute(module, @stack, [%Scope{}])
+    Module.put_attribute(module, @stack, [])
+    Module.put_attribute(module, @top, %Scope{})
     Module.put_attribute(module, @pipes, MapSet.new)
   end
 
@@ -23,9 +25,10 @@ defmodule Phoenix.Router.Scope do
     private = Keyword.get(opts, :private, %{})
     assigns = Keyword.get(opts, :assigns, %{})
     as      = Keyword.get(opts, :as, Phoenix.Naming.resource_name(plug, "Controller"))
+    alias?  = Keyword.get(opts, :alias, true)
 
     {path, host, alias, as, pipes, private, assigns} =
-      join(module, path, plug, as, private, assigns)
+      join(module, path, plug, alias?, as, private, assigns)
     Phoenix.Router.Route.build(line, kind, verb, path, host, alias, plug_opts, as, pipes, private, assigns)
   end
 
@@ -57,25 +60,15 @@ defmodule Phoenix.Router.Scope do
   """
   def pipe_through(module, new_pipes) do
     new_pipes = List.wrap(new_pipes)
-    stack_pipes =
-      module
-      |> get_stack()
-      |> Enum.flat_map(fn scope -> scope.pipes end)
-
-    update_stack(module, fn [scope | stack] ->
-      pipes = collect_pipes(new_pipes, stack_pipes, scope.pipes)
-      [put_in(scope.pipes, pipes) | stack]
-    end)
-  end
-  defp collect_pipes([] = _new_pipes, _stack_pipes, acc), do: acc
-  defp collect_pipes([pipe | new_pipes], stack_pipes, acc) do
-    if pipe in new_pipes or pipe in stack_pipes do
-      raise ArgumentError, """
-      duplicate pipe_through for #{inspect pipe}.
-      A plug may only be used once inside a scoped pipe_through
-      """
+    %{pipes: pipes} = top = get_top(module)
+
+    if pipe = Enum.find(new_pipes, & &1 in pipes) do
+      raise ArgumentError,
+            "duplicate pipe_through for #{inspect pipe}. " <>
+              "A plug may only be used once inside a scoped pipe_through"
     end
-    collect_pipes(new_pipes, stack_pipes, acc ++ [pipe])
+
+    put_top(module, %{top | pipes: pipes ++ new_pipes})
   end
 
   @doc """
@@ -86,36 +79,43 @@ defmodule Phoenix.Router.Scope do
   end
 
   def push(module, opts) when is_list(opts) do
-    path = with path when not is_nil(path) <- Keyword.get(opts, :path),
-                path <- validate_path(path),
-                do: String.split(path, "/", trim: true)
-
-    alias = Keyword.get(opts, :alias)
-    alias = alias && Atom.to_string(alias)
+    path =
+      if path = Keyword.get(opts, :path) do
+        path |> validate_path() |> String.split("/", trim: true)
+      else
+        []
+      end
+
+    alias = Keyword.get(opts, :alias) |> List.wrap() |> Enum.map(&Atom.to_string/1)
+    as = Keyword.get(opts, :as) |> List.wrap()
+    host = Keyword.get(opts, :host)
+    private = Keyword.get(opts, :private, %{})
+    assigns = Keyword.get(opts, :assigns, %{})
 
-    scope = %Scope{path: path,
-                   alias: alias,
-                   as: Keyword.get(opts, :as),
-                   host: Keyword.get(opts, :host),
-                   pipes: [],
-                   private: Keyword.get(opts, :private, %{}),
-                   assigns: Keyword.get(opts, :assigns, %{})}
+    top = get_top(module)
+    update_stack(module, fn stack -> [top | stack] end)
 
-    update_stack(module, fn stack -> [scope|stack] end)
+    put_top(module, %Scope{
+      path: top.path ++ path,
+      alias: top.alias ++ alias,
+      as: top.as ++ as,
+      host: host || top.host,
+      pipes: top.pipes,
+      private: Map.merge(top.private, private),
+      assigns: Map.merge(top.assigns, assigns)
+    })
   end
 
   @doc """
   Pops a scope from the module stack.
   """
   def pop(module) do
-    update_stack(module, fn [_|stack] -> stack end)
+    update_stack(module, fn [top | stack] ->
+      put_top(module, top)
+      stack
+    end)
   end
 
-  @doc """
-  Returns true if the module's definition is currently within a scope block.
-  """
-  def inside_scope?(module), do: length(get_stack(module)) > 1
-
   @doc """
   Add a forward to the router.
   """
@@ -132,70 +132,39 @@ defmodule Phoenix.Router.Scope do
     raise ArgumentError, "forward expects a module as the second argument, #{inspect plug} given"
   end
 
-  defp expand_alias(module, alias) do
-    if inside_scope?(module) do
-      module
-      |> get_stack()
-      |> join_alias(alias)
-    else
-      alias
-    end
-  end
-
-  defp join(module, path, alias, as, private, assigns) do
-    stack = get_stack(module)
-    {join_path(stack, path), find_host(stack), join_alias(stack, alias),
-     join_as(stack, as), join_pipe_through(stack), join_private(stack, private),
-     join_assigns(stack, assigns)}
-  end
-
-  defp join_path(stack, path) do
-    "/" <>
-      ([String.split(path, "/", trim: true) | extract(stack, :path)]
-       |> Enum.reverse()
-       |> Enum.concat()
-       |> Enum.join("/"))
-  end
-
-  defp join_alias(stack, alias) when is_atom(alias) do
-    [alias|extract(stack, :alias)]
-    |> Enum.reverse()
-    |> Module.concat()
-  end
-
-  defp join_as(_stack, nil), do: nil
-  defp join_as(stack, as) when is_atom(as) or is_binary(as) do
-    [as|extract(stack, :as)]
-    |> Enum.reverse()
-    |> Enum.join("_")
+  @doc """
+  Expands the alias in the current router scope.
+  """
+  def expand_alias(module, alias) do
+    join_alias(get_top(module), alias)
   end
 
-  defp join_private(stack, private) do
-    Enum.reduce stack, private, &Map.merge(&1.private, &2)
-  end
+  defp join(module, path, alias, alias?, as, private, assigns) do
+    top = get_top(module)
+    joined_alias =
+      if alias? do
+        join_alias(top, alias)
+      else
+        alias
+      end
 
-  defp join_assigns(stack, assigns) do
-    Enum.reduce stack, assigns, &Map.merge(&1.assigns, &2)
+    {join_path(top, path), top.host, joined_alias, join_as(top, as), top.pipes,
+     Map.merge(top.private, private), Map.merge(top.assigns, assigns)}
   end
 
-  defp join_pipe_through(stack) do
-    for scope <- Enum.reverse(stack),
-        item <- scope.pipes,
-        do: item
+  defp join_path(top, path) do
+    "/" <> Enum.join(top.path ++ String.split(path, "/", trim: true), "/")
   end
 
-  defp find_host(stack) do
-    Enum.find_value(stack, & &1.host)
+  defp join_alias(top, alias) when is_atom(alias) do
+    Module.concat(top.alias ++ [alias])
   end
 
-  defp extract(stack, attr) do
-    for scope <- stack,
-        item = Map.fetch!(scope, attr),
-        do: item
-  end
+  defp join_as(_top, nil), do: nil
+  defp join_as(top, as) when is_atom(as) or is_binary(as), do: Enum.join(top.as ++ [as], "_")
 
-  defp get_stack(module) do
-    get_attribute(module, @stack)
+  defp get_top(module) do
+    get_attribute(module, @top)
   end
 
   defp update_stack(module, fun) do
@@ -206,6 +175,11 @@ defmodule Phoenix.Router.Scope do
     update_attribute(module, @pipes, fun)
   end
 
+  defp put_top(module, value) do
+    Module.put_attribute(module, @top, value)
+    value
+  end
+
   defp get_attribute(module, attr) do
     Module.get_attribute(module, attr) ||
       raise "Phoenix router scope was not initialized"
diff --git a/lib/phoenix/socket.ex b/lib/phoenix/socket.ex
index 01234dad2..d415e1483 100644
--- a/lib/phoenix/socket.ex
+++ b/lib/phoenix/socket.ex
@@ -68,13 +68,20 @@ defmodule Phoenix.Socket do
     * `:transport_pid` - The pid of the socket's transport process
     * `:serializer` - The serializer for socket messages
 
-  ## Logging
+  ## Using options
 
-  Logging for socket connections is set via the `:log` option, for example:
+  On `use Phoenix.Socket`, the following options are accepted:
 
-      use Phoenix.Socket, log: :debug
+    * `:log` - the default level to log socket actions. Defaults
+      to `:info`. May be set to `false` to disable it
 
-  Defaults to the `:info` log level. Pass `false` to disable logging.
+    * `:shutdown` - the maximum shutdown time of each channel
+      when the endpoint is shutting down. Applies only to
+      channel-based sockets
+
+    * `:partitions` - each channel is spawned under a supervisor.
+      This option controls how many supervisors will be spawned
+      to handlle channels. Defaults to the number of cores.
 
   ## Garbage collection
 
@@ -131,9 +138,9 @@ defmodule Phoenix.Socket do
       {auth_payload, from, socket}
 
   A custom channel implementation MUST invoke
-  `GenServer.reply(from, reply_payload)` during its initialization
-  with a custom `reply_payload` that will be sent as a reply to the
-  client. Failing to do so will block the socket forever.
+  `GenServer.reply(from, {:ok | :error, reply_payload})` during its
+  initialization with a custom `reply_payload` that will be sent as
+  a reply to the client. Failing to do so will block the socket forever.
 
   A custom channel receives `Phoenix.Socket.Message` structs as regular
   messages from the transport. Replies to those messages and custom
@@ -269,7 +276,7 @@ defmodule Phoenix.Socket do
       @behaviour Phoenix.Socket
       @before_compile Phoenix.Socket
       Module.register_attribute(__MODULE__, :phoenix_channels, accumulate: true)
-      @phoenix_log Keyword.get(unquote(opts), :log, :info)
+      @phoenix_socket_options unquote(opts)
 
       ## Callbacks
 
@@ -277,11 +284,11 @@ defmodule Phoenix.Socket do
 
       @doc false
       def child_spec(opts) do
-        Phoenix.Socket.__child_spec__(__MODULE__, opts)
+        Phoenix.Socket.__child_spec__(__MODULE__, opts, @phoenix_socket_options)
       end
 
       @doc false
-      def connect(map), do: Phoenix.Socket.__connect__(__MODULE__, map, @phoenix_log)
+      def connect(map), do: Phoenix.Socket.__connect__(__MODULE__, map, @phoenix_socket_options)
 
       @doc false
       def init(state), do: Phoenix.Socket.__init__(state)
@@ -400,11 +407,13 @@ defmodule Phoenix.Socket do
 
   ## CALLBACKS IMPLEMENTATION
 
-  def __child_spec__(handler, opts) do
+  def __child_spec__(handler, opts, socket_options) do
     import Supervisor.Spec
     endpoint = Keyword.fetch!(opts, :endpoint)
+
+    opts = Keyword.merge(socket_options, opts)
     shutdown = Keyword.get(opts, :shutdown, 5_000)
-    partitions = Keyword.get(opts, :partitions) || System.schedulers_online()
+    partitions = Keyword.get(opts, :partitions, System.schedulers_online())
 
     worker_opts = [shutdown: shutdown, restart: :temporary]
     worker = worker(Phoenix.Channel.Server, [], worker_opts)
@@ -412,7 +421,7 @@ defmodule Phoenix.Socket do
     supervisor(Phoenix.Socket.PoolSupervisor, [args], id: handler)
   end
 
-  def __connect__(user_socket, map, log) do
+  def __connect__(user_socket, map, socket_options) do
     %{
       endpoint: endpoint,
       options: options,
@@ -420,7 +429,10 @@ defmodule Phoenix.Socket do
       params: params,
       connect_info: connect_info
     } = map
+
     vsn = params["vsn"] || "1.0.0"
+    options = Keyword.merge(socket_options, options)
+    log = Keyword.get(options, :log, :info)
     meta = Map.merge(map, %{vsn: vsn, user_socket: user_socket, log: log})
 
     Phoenix.Endpoint.instrument(endpoint, :phoenix_socket_connect, meta, fn ->
diff --git a/lib/phoenix/token.ex b/lib/phoenix/token.ex
index d10568238..41ee3ad5d 100644
--- a/lib/phoenix/token.ex
+++ b/lib/phoenix/token.ex
@@ -233,6 +233,8 @@ defmodule Phoenix.Token do
     false
   end
 
+  defp expired?(signed, max_age_secs) when max_age_secs <= 0, do: true
+
   defp expired?(signed, max_age_secs), do: (signed + trunc(max_age_secs * 1000)) < now_ms()
 
   defp now_ms, do: System.system_time(:millisecond)
diff --git a/mix.exs b/mix.exs
index fc43e63f6..f5f332bd7 100644
--- a/mix.exs
+++ b/mix.exs
@@ -22,7 +22,7 @@ defmodule Phoenix.MixProject do
       homepage_url: "http://www.phoenixframework.org",
       description: """
       Productive. Reliable. Fast. A productive web framework that
-      does not compromise speed and maintainability.
+      does not compromise speed or maintainability.
       """
     ]
   end


Test patch:
diff --git a/guides/testing/testing_channels.md b/guides/testing/testing_channels.md
index 17b947ef1..8acb11f95 100644
--- a/guides/testing/testing_channels.md
+++ b/guides/testing/testing_channels.md
@@ -168,6 +168,8 @@ Since the `handle_in/3` callback for the `"shout"` event just broadcasts the sam
 all subscribers in the `"room:lobby"` should receive the message. To check that, we do
 `assert_broadcast "shout", %{"hello" => "all"}`.
 
+**NOTE:** `assert_broadcast/3` tests that the message was broadcast in the PubSub system.
+  For testing if a client receives a message, use `assert_push/3`
 
 #### Testing an Asynchronous Push from the Server
 
diff --git a/test/mix/tasks/phx.gen.context_test.exs b/test/mix/tasks/phx.gen.context_test.exs
index 8ca5a4d71..af3920e42 100644
--- a/test/mix/tasks/phx.gen.context_test.exs
+++ b/test/mix/tasks/phx.gen.context_test.exs
@@ -104,6 +104,14 @@ defmodule Mix.Tasks.Phx.Gen.ContextTest do
         Gen.Context.run(~w(Blog Blog blogs))
       end
 
+      assert_raise Mix.Error, ~r/Cannot generate context Phoenix because it has the same name as the application/, fn ->
+        Gen.Context.run(~w(Phoenix Post blogs))
+      end
+
+      assert_raise Mix.Error, ~r/Cannot generate schema Phoenix because it has the same name as the application/, fn ->
+        Gen.Context.run(~w(Blog Phoenix blogs))
+      end
+
       assert_raise Mix.Error, ~r/Invalid arguments/, fn ->
         Gen.Context.run(~w(Blog.Post posts))
       end
diff --git a/test/phoenix/integration/websocket_channels_test.exs b/test/phoenix/integration/websocket_channels_test.exs
index 526a495e4..66c6bc76e 100644
--- a/test/phoenix/integration/websocket_channels_test.exs
+++ b/test/phoenix/integration/websocket_channels_test.exs
@@ -70,12 +70,13 @@ defmodule Phoenix.Integration.WebSocketChannelsTest do
     def init({payload, from, socket}) do
       case payload["action"] do
         "ok" ->
-          GenServer.reply(from, %{"action" => "ok"})
+          GenServer.reply(from, {:ok, %{"action" => "ok"}})
           {:ok, socket}
 
         "ignore" ->
-          GenServer.reply(from, %{"action" => "ignore"})
-          :ignore
+          GenServer.reply(from, {:error, %{"action" => "ignore"}})
+          send(self(), :stop)
+          {:ok, socket}
 
         "error" ->
           raise "oops"
@@ -86,6 +87,10 @@ defmodule Phoenix.Integration.WebSocketChannelsTest do
       send socket.transport_pid, {:socket_close, self(), :shutdown}
       {:stop, :shutdown, socket}
     end
+
+    def handle_info(:stop, socket) do
+      {:stop, :shutdown, socket}
+    end
   end
 
   defmodule UserSocketConnectInfo do
diff --git a/test/phoenix/router/pipeline_test.exs b/test/phoenix/router/pipeline_test.exs
index 1e0fa83a5..4268857ab 100644
--- a/test/phoenix/router/pipeline_test.exs
+++ b/test/phoenix/router/pipeline_test.exs
@@ -142,7 +142,8 @@ defmodule Phoenix.Router.PipelineTest do
         pipeline :browser do
         end
         scope "/" do
-          pipe_through [:browser, :auth, :browser]
+          pipe_through [:browser, :auth]
+          pipe_through [:browser]
         end
       end
     end
diff --git a/test/phoenix/router/scope_test.exs b/test/phoenix/router/scope_test.exs
index 8adb2974f..1a5d1826c 100644
--- a/test/phoenix/router/scope_test.exs
+++ b/test/phoenix/router/scope_test.exs
@@ -11,6 +11,10 @@ defmodule Phoenix.Router.ScopedRoutingTest do
     def edit(conn, _params), do: text(conn, "api v1 users edit")
     def foo_host(conn, _params), do: text(conn, "foo request from #{conn.host}")
     def baz_host(conn, _params), do: text(conn, "baz request from #{conn.host}")
+    def proxy(conn, _) do
+      {controller, action} = conn.private.proxy_to
+      controller.call(conn, controller.init(action))
+    end
   end
 
   defmodule Router do
@@ -42,6 +46,9 @@ defmodule Phoenix.Router.ScopedRoutingTest do
 
       scope "/v1", alias: V1 do
         resources "/users", UserController, only: [:delete], private: %{private_token: "baz"}
+        get "/noalias", Api.V1.UserController, :proxy,
+          private: %{proxy_to: {scoped_alias(__MODULE__, UserController), :show}},
+          alias: false
       end
     end
 
@@ -192,4 +199,10 @@ defmodule Phoenix.Router.ScopedRoutingTest do
       end
     end
   end
+
+  test "alias false with expanded scoped alias" do
+    conn = call(Router, :get, "/api/v1/noalias")
+    assert conn.status == 200
+    assert conn.resp_body == "api v1 users show"
+  end
 end
diff --git a/test/phoenix/token_test.exs b/test/phoenix/token_test.exs
index e2b694598..d54754a3b 100644
--- a/test/phoenix/token_test.exs
+++ b/test/phoenix/token_test.exs
@@ -46,6 +46,7 @@ defmodule Phoenix.TokenTest do
     assert Token.verify(conn(), "id", token, max_age: -1000) == {:error, :expired}
     assert Token.verify(conn(), "id", token, max_age: 100) == {:ok, 1}
     assert Token.verify(conn(), "id", token, max_age: -100) == {:error, :expired}
+    assert Token.verify(conn(), "id", token, max_age: 0) == {:error, :expired}
 
     token = Token.sign(conn(), "id", 1)
     assert Token.verify(conn(), "id", token, max_age: 0.1) == {:ok, 1}