Repository: phoenixframework/phoenix
Pull request #2957 (2018-07-12 15:41:42)

changed guides mentioning *_path and moduledoc in lib/phoenix/view.ex
I think I changed it in all relevant points. I also changed the notes/explanations, let me know if the language is fine and if anything else is missing/needs change. I tried rgrep for _path outside the guides, but it's a never ending list of hits for unrelated stuff, I don't think I have missed something but it could happen

Gazler: There's also the following reference which needs updating:

`./channels.md:404:<script src="<%= static_path(@conn, "/js/app.js") %>"></script>`

mnussbaumer: @Gazler will do these changes later today, I also noticed in the module doc I left a <% end %> statement that I will remove too

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b597d87fa..73dac2966 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,6 +37,7 @@ The old APIs for building transports are also deprecated. The good news is: adap
   * [Endpoint] Add `Cowboy2Adapter` for HTTP2 support with cowboy2
   * [Endpoint] The `socket/3` macro now accepts direct configuration about websockets and longpoll
   * [Endpoint] Support MFA function in `:check_origin` config for custom origin checking
+  * [Endpoint] Add new `:phoenix_error_render` instrumentation callback
   * [Logger] Add whitelist support to `filter_parameters` logger configuration, via new `:keep` tuple format
   * [Phoenix] Add `Phoenix.json_library/0` and replace `Poison` with `Jason` for JSON encoding in new projects
   * [Router] Display list of available routes on debugger 404 error page
diff --git a/guides/channels.md b/guides/channels.md
index 024666453..9537735d0 100644
--- a/guides/channels.md
+++ b/guides/channels.md
@@ -181,7 +181,7 @@ Phoenix ships with a JavaScript client that is available when generating a new P
   - [dn-phoenix](https://github.com/jfis/dn-phoenix)
 
 ## Tying it all together
-Let's tie all these ideas together by building a simple chat application. After [generating a new Phoenix application](http://www.phoenixframework.org/docs/up-and-running) we'll see that the endpoint is already set up for us in `lib/hello_web/endpoint.ex`:
+Let's tie all these ideas together by building a simple chat application. After [generating a new Phoenix application](https://hexdocs.pm/phoenix/up_and_running.html) we'll see that the endpoint is already set up for us in `lib/hello_web/endpoint.ex`:
 
 ```elixir
 defmodule HelloWeb.Endpoint do
@@ -401,7 +401,7 @@ Next we need to pass this token to JavaScript. We can do so inside a script tag
 
 ```html
 <script>window.userToken = "<%= assigns[:user_token] %>";</script>
-<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
+<script src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
 ```
 
 **Step 3 - Pass the Token to the Socket Constructor and Verify**
diff --git a/guides/contexts.md b/guides/contexts.md
index d1776e1db..9db624304 100644
--- a/guides/contexts.md
+++ b/guides/contexts.md
@@ -147,7 +147,7 @@ defmodule HelloWeb.UserController do
       {:ok, user} ->
         conn
         |> put_flash(:info, "User created successfully.")
-        |> redirect(to: user_path(conn, :show, user))
+        |> redirect(to: Routes.user_path(conn, :show, user))
       {:error, %Ecto.Changeset{} = changeset} ->
         render(conn, "new.html", changeset: changeset)
     end
@@ -480,7 +480,7 @@ defmodule HelloWeb.SessionController do
       {:error, :unauthorized} ->
         conn
         |> put_flash(:error, "Bad email/password combination")
-        |> redirect(to: session_path(conn, :new))
+        |> redirect(to: Routes.session_path(conn, :new))
     end
   end
 
@@ -540,7 +540,7 @@ Next, add a new template in `lib/hello_web/templates/session/new.html.eex:`
 ```eex
 <h1>Sign in</h1>
 
-<%= form_for @conn, session_path(@conn, :create), [method: :post, as: :user], fn f -> %>
+<%= form_for @conn, Routes.session_path(@conn, :create), [method: :post, as: :user], fn f -> %>
   <div class="form-group">
     <%= text_input f, :email, placeholder: "Email" %>
   </div>
@@ -554,7 +554,7 @@ Next, add a new template in `lib/hello_web/templates/session/new.html.eex:`
   </div>
 <% end %>
 
-<%= form_for @conn, session_path(@conn, :delete), [method: :delete, as: :user], fn _ -> %>
+<%= form_for @conn, Routes.session_path(@conn, :delete), [method: :delete, as: :user], fn _ -> %>
   <div class="form-group">
     <%= submit "logout" %>
   </div>
@@ -893,7 +893,7 @@ Open up your generated `lib/hello_web/controllers/cms/page_controller.ex` and ma
     else
       conn
       |> put_flash(:error, "You can't modify that page")
-      |> redirect(to: cms_page_path(conn, :index))
+      |> redirect(to: Routes.cms_page_path(conn, :index))
       |> halt()
     end
   end
@@ -921,7 +921,7 @@ With our new plugs in place, we can now modify our `create`, `edit`, `update`, a
       {:ok, page} ->
         conn
         |> put_flash(:info, "Page created successfully.")
-        |> redirect(to: cms_page_path(conn, :show, page))
+        |> redirect(to: Routes.cms_page_path(conn, :show, page))
       {:error, %Ecto.Changeset{} = changeset} ->
         render(conn, "new.html", changeset: changeset)
     end
@@ -935,7 +935,7 @@ With our new plugs in place, we can now modify our `create`, `edit`, `update`, a
       {:ok, page} ->
         conn
         |> put_flash(:info, "Page updated successfully.")
-        |> redirect(to: cms_page_path(conn, :show, page))
+        |> redirect(to: Routes.cms_page_path(conn, :show, page))
       {:error, %Ecto.Changeset{} = changeset} ->
 -       render(conn, "edit.html", page: page, changeset: changeset)
 +       render(conn, "edit.html", changeset: changeset)
@@ -950,7 +950,7 @@ With our new plugs in place, we can now modify our `create`, `edit`, `update`, a
 
     conn
     |> put_flash(:info, "Page deleted successfully.")
-    |> redirect(to: cms_page_path(conn, :index))
+    |> redirect(to: Routes.cms_page_path(conn, :index))
   end
 ```
 
diff --git a/guides/controllers.md b/guides/controllers.md
index 2d5dda81f..0290636be 100644
--- a/guides/controllers.md
+++ b/guides/controllers.md
@@ -518,7 +518,7 @@ defmodule HelloWeb.PageController do
   use HelloWeb, :controller
 
   def index(conn, _params) do
-    redirect(conn, to: redirect_test_path(conn, :redirect_test))
+    redirect(conn, to: Routes.redirect_test_path(conn, :redirect_test))
   end
 end
 ```
@@ -527,7 +527,7 @@ Note that we can't use the url helper here because `redirect/2` using the atom `
 
 ```elixir
 def index(conn, _params) do
-  redirect(conn, to: redirect_test_url(conn, :redirect_test))
+  redirect(conn, to: Routes.redirect_test_url(conn, :redirect_test))
 end
 ```
 
@@ -535,7 +535,7 @@ If we want to use the url helper to pass a full url to `redirect/2`, we must use
 
 ```elixir
 def index(conn, _params) do
-  redirect(conn, external: redirect_test_url(conn, :redirect_test))
+  redirect(conn, external: Routes.redirect_test_url(conn, :redirect_test))
 end
 ```
 
diff --git a/guides/deployment/heroku.md b/guides/deployment/heroku.md
index 1c57adda4..a9940e10d 100644
--- a/guides/deployment/heroku.md
+++ b/guides/deployment/heroku.md
@@ -2,7 +2,7 @@
 
 ### What we'll need
 
-The only thing we'll need for this guide is a working Phoenix application. For those of us who need a simple application to deploy, please follow the [Up and Running guide](http://www.phoenixframework.org/docs/up-and-running).
+The only thing we'll need for this guide is a working Phoenix application. For those of us who need a simple application to deploy, please follow the [Up and Running guide](https://hexdocs.pm/phoenix/up_and_running.html).
 
 ### Goals
 
diff --git a/guides/errors.md b/guides/errors.md
index e44a9e7a9..b7ff268fe 100644
--- a/guides/errors.md
+++ b/guides/errors.md
@@ -36,7 +36,7 @@ config :hello, HelloWeb.Endpoint,
   debug_errors: false,
   code_reloader: true,
   cache_static_lookup: false,
-  watchers: [node: ["node_modules/webpack/bin/webpack.js", "--mode", "development", "--watch-stdin",
+  watchers: [node: ["node_modules/webpack/bin/webpack.js", "--mode", "development", "--watch-stdin", "--colors",
                     cd: Path.expand("../assets", __DIR__)]]
 ```
 
diff --git a/guides/phoenix_mix_tasks.md b/guides/phoenix_mix_tasks.md
index a4a2f139c..3cacf7d15 100644
--- a/guides/phoenix_mix_tasks.md
+++ b/guides/phoenix_mix_tasks.md
@@ -225,17 +225,14 @@ Remember to update your repository by running migrations:
     $ mix ecto.migrate
 ```
 
-Important: If we don't do this, our application won't compile, and we'll get an error.
+Important: If we don't do this, we will see the following warnings in our logs, and our application will error when trying to execute the function.
 
 ```console
 $ mix phx.server
 Compiling 17 files (.ex)
 
-== Compilation error in file lib/hello_web/controllers/post_controller.ex ==
-** (CompileError) lib/hello_web/controllers/post_controller.ex:22: undefined function post_path/3
-    (stdlib) lists.erl:1338: :lists.foreach/2
-    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
-    (elixir) lib/kernel/parallel_compiler.ex:121: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1
+warning: function HelloWeb.Router.Helpers.post_path/3 is undefined or private
+  lib/hello_web/controllers/post_controller.ex:22: 
 ```
 
 If we don't want to create a context or schema for our resource we can use the `--no-context` flag. Note that this still requires a context module name as a parameter.
@@ -260,17 +257,14 @@ Add the resource to your browser scope in lib/hello_web/router.ex:
     resources "/posts", PostController
 ```
 
-Important: If we don't do this, our application won't compile, and we'll get an error.
+Important: If we don't do this, we'll get the following warning in our logs and the application will error when attempting to load the page:
 
 ```console
 $ mix phx.server
 Compiling 15 files (.ex)
 
-== Compilation error in file lib/hello_web/views/post_view.ex ==
-** (CompileError) lib/hello_web/templates/post/edit.html.eex:3: undefined function post_path/3
-    (stdlib) lists.erl:1338: :lists.foreach/2
-    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
-    (elixir) lib/kernel/parallel_compiler.ex:121: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1
+warning: function HelloWeb.Router.Helpers.post_path/3 is undefined or private
+  lib/hello_web/templates/post/edit.html.eex:3
 ```
 
 Similarly - if we want a context created without a schema for our resource we can use the `--no-schema` flag.
@@ -299,17 +293,14 @@ Add the resource to your browser scope in lib/hello_web/router.ex:
     resources "/posts", PostController
 ```
 
-Important: If we don't do this, our application won't compile, and we'll get an error.
+Important: If we don't do this, we'll get the following warning in our logs and the application will error when attempting to load the page:
 
 ```console
 $ mix phx.server
 Compiling 15 files (.ex)
 
-== Compilation error in file lib/hello_web/views/post_view.ex ==
-** (CompileError) lib/hello_web/templates/post/edit.html.eex:3: undefined function post_path/3
-    (stdlib) lists.erl:1338: :lists.foreach/2
-    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
-    (elixir) lib/kernel/parallel_compiler.ex:121: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1
+warning: function HelloWeb.Router.Helpers.post_path/3 is undefined or private
+  lib/hello_web/templates/post/edit.html.eex:3
 ```
 
 #### [mix phx.gen.json](`Mix.Tasks.Phx.Gen.Json.run/1`)
@@ -346,17 +337,14 @@ Remember to update your repository by running migrations:
     $ mix ecto.migrate
 ```
 
-Important: If we don't do this, our application won't compile, and we'll get an error.
+Important: If we don't do this, we'll get the following warning in our logs and the application will error when attempting to load the page:
 
 ```console
 $ mix phx.server
 Compiling 19 files (.ex)
 
-== Compilation error in file lib/hello_web/controllers/post_controller.ex ==
-** (CompileError) lib/hello_web/controllers/post_controller.ex:18: undefined function post_path/3
-    (stdlib) lists.erl:1338: :lists.foreach/2
-    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
-    (elixir) lib/kernel/parallel_compiler.ex:121: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1
+warning: function HelloWeb.Router.Helpers.post_path/3 is undefined or private
+  lib/hello_web/controllers/post_controller.ex:18
 ```
 
 If we don't want to create a context or schema for our resource we can use the `--no-context` flag. Note that this still requires a context module name as a parameter.
diff --git a/guides/presence.md b/guides/presence.md
index 0f852eb02..1b00ea84c 100644
--- a/guides/presence.md
+++ b/guides/presence.md
@@ -88,7 +88,7 @@ defmodule HelloWeb.RoomChannel do
   def handle_info(:after_join, socket) do
     push(socket, "presence_state", Presence.list(socket))
     {:ok, _} = Presence.track(socket, socket.assigns.user_id, %{
-      online_at: inspect(System.system_time(:seconds))
+      online_at: inspect(System.system_time(:second))
     })
     {:noreply, socket}
   end
diff --git a/guides/routing.md b/guides/routing.md
index 85603abf2..eb4195963 100644
--- a/guides/routing.md
+++ b/guides/routing.md
@@ -250,10 +250,10 @@ iex> HelloWeb.Router.Helpers.page_path(HelloWeb.Endpoint, :index)
 This is significant because we can use the `page_path` function in a template to link to the root of our application. We can then use this helper in our templates:
 
 ```html
-<a href="<%= page_path(@conn, :index) %>">To the Welcome Page!</a>
+<a href="<%= Routes.page_path(@conn, :index) %>">To the Welcome Page!</a>
 ```
 
-The `page_path` function is imported into our template with `use HelloWeb, :view`. Please see the [View Guide](views.html) for more information.
+The reason we can use `Routes.page_path` instead of the full `HelloWeb.Router.Helpers.page_path` name is because `HelloWeb.Router.Helpers` is aliased as `Routes` by default in the `view/0` definition (`lib/hello_web.ex`) and made available to our templates through `use HelloWeb, :view`. We can, of course, use `HelloWeb.Router.Helpers.page_path(@conn, :index)` instead, but the convention is to use the aliased version for conciseness (note that the alias is only set automatically for use in views, controllers and templates - outside these you need either the full name, or to alias it yourself inside the module definition: `alias HelloWeb.Router.Helpers, as: Routes`). Please see the [View Guide](views.html) for more information.
 
 This pays off tremendously if we should ever have to change the path of our route in the router. Since the path helpers are built dynamically from the routes, any calls to `page_path` in our templates will still work.
 
@@ -262,41 +262,41 @@ This pays off tremendously if we should ever have to change the path of our rout
 When we ran the `phx.routes` task for our user resource, it listed the `user_path` as the path helper function for each line of output. Here is what that translates to for each action:
 
 ```elixir
-iex> import HelloWeb.Router.Helpers
+iex> alias HelloWeb.Router.Helpers, as: Routes
 iex> alias HelloWeb.Endpoint
-iex> user_path(Endpoint, :index)
+iex> Routes.user_path(Endpoint, :index)
 "/users"
 
-iex> user_path(Endpoint, :show, 17)
+iex> Routes.user_path(Endpoint, :show, 17)
 "/users/17"
 
-iex> user_path(Endpoint, :new)
+iex> Routes.user_path(Endpoint, :new)
 "/users/new"
 
-iex> user_path(Endpoint, :create)
+iex> Routes.user_path(Endpoint, :create)
 "/users"
 
-iex> user_path(Endpoint, :edit, 37)
+iex> Routes.user_path(Endpoint, :edit, 37)
 "/users/37/edit"
 
-iex> user_path(Endpoint, :update, 37)
+iex> Routes.user_path(Endpoint, :update, 37)
 "/users/37"
 
-iex> user_path(Endpoint, :delete, 17)
+iex> Routes.user_path(Endpoint, :delete, 17)
 "/users/17"
 ```
 
 What about paths with query strings? By adding an optional fourth argument of key value pairs, the path helpers will return those pairs in the query string.
 
 ```elixir
-iex> user_path(Endpoint, :show, 17, admin: true, active: false)
+iex> Routes.user_path(Endpoint, :show, 17, admin: true, active: false)
 "/users/17?admin=true&active=false"
 ```
 
 What if we need a full url instead of a path? Just replace `_path` with `_url`:
 
 ```elixir
-iex(3)> user_url(Endpoint, :index)
+iex(3)> Routes.user_url(Endpoint, :index)
 "http://localhost:4000/users"
 ```
 
@@ -344,6 +344,15 @@ iex> HelloWeb.Router.Helpers.user_post_path(Endpoint, :index, 42, active: true)
 "/users/42/posts?active=true"
 ```
 
+If we had aliased the `Helpers` module as before (it is only automatically aliased for views, templates and controllers, in this case, since we're inside `iex` we need to do it ourselves), we could instead do:
+
+```elixir
+iex> alias HelloWeb.Router.Helpers, as: Routes
+iex> alias HelloWeb.Endpoint
+iex> Routes.user_post_path(Endpoint, :index, 42, active: true)
+"/users/42/posts?active=true"
+```
+
 ## Scoped Routes
 
 Scopes are a way to group routes under a common path prefix and scoped set of plug middleware. We might want to do this for admin functionality, APIs, and especially for versioned APIs. Let's say we have user generated reviews on a site, and that those reviews first need to be approved by an admin. The semantics of these resources are quite different, and they might not share the same controller. Scopes enable us to segregate these routes.
diff --git a/guides/up_and_running.md b/guides/up_and_running.md
index 43f686091..c010a5679 100644
--- a/guides/up_and_running.md
+++ b/guides/up_and_running.md
@@ -114,4 +114,4 @@ If your screen looks like the image above, congratulations! You now have a worki
 
 Locally, our application is running in an `iex` session. To stop it, we hit `ctrl-c` twice, just as we would to stop `iex` normally.
 
-[The next step](http://www.phoenixframework.org/docs/adding-pages) is customizing our application just a bit to give us a sense of how a Phoenix app is put together.
+[The next step](https://hexdocs.pm/phoenix/adding_pages.html) is customizing our application just a bit to give us a sense of how a Phoenix app is put together.
diff --git a/guides/views.md b/guides/views.md
index 62af400ed..cf2661602 100644
--- a/guides/views.md
+++ b/guides/views.md
@@ -67,7 +67,8 @@ rendering with assigns [:conn, :view_module, :view_template]
 
 Pretty neat, right? At compile-time, Phoenix precompiles all `*.html.eex` templates and turns them into `render/2` function clauses on their respective view modules. At runtime, all templates are already loaded in memory. There's no disk reads, complex file caching, or template engine computation involved. This is also why we were able to define functions like `title/0` in our `LayoutView` and they were immediately available inside the layout's `app.html.eex` – the call to `title/0` was just a local function call!
 
-When we `use HelloWeb, :view`, we get other conveniences as well. Since the `view/0` function imports `HelloWeb.Router.Helpers`, we don't have to fully qualify path helpers in templates. Let's see how that works by changing the template for our Welcome to Phoenix page.
+When we `use HelloWeb, :view`, we get other conveniences as well. Since `view/0` aliases `HelloWeb.Router.Helpers` as `Routes` (look in `lib/hello_web.ex`), we can simply call these helpers by using `Routes.*_path` in templates. Let's see how that works by changing the template for our Welcome to Phoenix page.
+
 
 Let's open up the `lib/hello_web/templates/page/index.html.eex` and locate this stanza.
 
@@ -84,7 +85,7 @@ Then let's add a line with a link back to the same page. (The objective is to se
 <div class="jumbotron">
   <h2><%= gettext("Welcome to %{name}!", name: "Phoenix") %></h2>
   <p class="lead">A productive web framework that<br>does not compromise speed and maintainability.</p>
-  <p><a href="<%= page_path(@conn, :index) %>">Link back to this page</a></p>
+  <p><a href="<%= Routes.page_path(@conn, :index) %>">Link back to this page</a></p>
 </div>
 ```
 
@@ -94,7 +95,9 @@ Now we can reload the page and view source to see what we have.
 <a href="/">Link back to this page</a>
 ```
 
-Great, `page_path/2` evaluated to `/` as we would expect, and we didn't need to qualify it with `Phoenix.View`.
+Great, `Routes.page_path/2` evaluated to `/` as we would expect, we just had to use the alias set in `Phoenix.View`.
+
+If you happen to need access to the path helpers outside views, controllers or templates, you can either call them by the full qualified name, e.g. `HelloWeb.Router.Helpers.page_path(@conn, :index)` or alias it yourself in the calling module, by defining `alias HelloWeb.Router.Helpers, as: Routes` in the module you want to use, and then calling, e.g., `Routes.page_path(@conn, :index)`.
 
 ### More About Views
 
@@ -248,7 +251,7 @@ Great, so we have a `render/2` function that takes a template and an `assigns` m
     <div class="container">
       <div class="header">
         <ul class="nav nav-pills pull-right">
-          <li><a href="http://www.phoenixframework.org/docs">Get Started</a></li>
+          <li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
         </ul>
         <span class="logo"></span>
       </div>
diff --git a/installer/templates/phx_single/README.md b/installer/templates/phx_single/README.md
index 9cd5bf0ee..8480b0a3d 100644
--- a/installer/templates/phx_single/README.md
+++ b/installer/templates/phx_single/README.md
@@ -9,12 +9,12 @@ To start your Phoenix server:
 
 Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
 
-Ready to run in production? Please [check our deployment guides](http://www.phoenixframework.org/docs/deployment).
+Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html).
 
 ## Learn more
 
   * Official website: http://www.phoenixframework.org/
-  * Guides: http://phoenixframework.org/docs/overview
+  * Guides: https://hexdocs.pm/phoenix/overview.html
   * Docs: https://hexdocs.pm/phoenix
   * Mailing list: http://groups.google.com/group/phoenix-talk
   * Source: https://github.com/phoenixframework/phoenix
diff --git a/installer/templates/phx_single/config/dev.exs b/installer/templates/phx_single/config/dev.exs
index fb25c07c2..427797a49 100644
--- a/installer/templates/phx_single/config/dev.exs
+++ b/installer/templates/phx_single/config/dev.exs
@@ -11,7 +11,7 @@ config :<%= app_name %>, <%= endpoint_module %>,
   debug_errors: true,
   code_reloader: true,
   check_origin: false,
-  watchers: <%= if webpack do %>[node: ["node_modules/webpack/bin/webpack.js", "--mode", "development", "--watch-stdin",
+  watchers: <%= if webpack do %>[node: ["node_modules/webpack/bin/webpack.js", "--mode", "development", "--watch-stdin", "--colors",
                     cd: Path.expand("../assets", __DIR__)]]<% else %>[]<% end %>
 
 # ## SSL Support
diff --git a/installer/templates/phx_single/mix.exs b/installer/templates/phx_single/mix.exs
index f6efa74d7..4e3d5f17c 100644
--- a/installer/templates/phx_single/mix.exs
+++ b/installer/templates/phx_single/mix.exs
@@ -59,7 +59,7 @@ defmodule <%= app_module %>.MixProject do
     [
       "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
       "ecto.reset": ["ecto.drop", "ecto.setup"],
-      "test": ["ecto.create --quiet", "ecto.migrate", "test"]
+      test: ["ecto.create --quiet", "ecto.migrate", "test"]
     ]
   end<% end %>
 end
diff --git a/installer/templates/phx_umbrella/apps/app_name/mix.exs b/installer/templates/phx_umbrella/apps/app_name/mix.exs
index af171fa34..472f4b23b 100644
--- a/installer/templates/phx_umbrella/apps/app_name/mix.exs
+++ b/installer/templates/phx_umbrella/apps/app_name/mix.exs
@@ -51,7 +51,7 @@ defmodule <%= app_module %>.MixProject do
     [<%= if ecto do %>
       "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
       "ecto.reset": ["ecto.drop", "ecto.setup"],
-      "test": ["ecto.create --quiet", "ecto.migrate", "test"]
+      test: ["ecto.create --quiet", "ecto.migrate", "test"]
     <% end %>]
   end
 end
diff --git a/installer/templates/phx_umbrella/apps/app_name_web/README.md b/installer/templates/phx_umbrella/apps/app_name_web/README.md
index 568e27d24..ec69404ee 100644
--- a/installer/templates/phx_umbrella/apps/app_name_web/README.md
+++ b/installer/templates/phx_umbrella/apps/app_name_web/README.md
@@ -9,12 +9,12 @@ To start your Phoenix server:
 
 Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
 
-Ready to run in production? Please [check our deployment guides](http://www.phoenixframework.org/docs/deployment).
+Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html).
 
 ## Learn more
 
   * Official website: http://www.phoenixframework.org/
-  * Guides: http://phoenixframework.org/docs/overview
+  * Guides: https://hexdocs.pm/phoenix/overview.html
   * Docs: https://hexdocs.pm/phoenix
   * Mailing list: http://groups.google.com/group/phoenix-talk
   * Source: https://github.com/phoenixframework/phoenix
diff --git a/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs b/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
index 63f46513b..5c703d9d4 100644
--- a/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
+++ b/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
@@ -15,7 +15,7 @@ config :<%= web_app_name %>, <%= endpoint_module %>,
   debug_errors: true,
   code_reloader: true,
   check_origin: false,
-  watchers: <%= if webpack do %>[node: ["node_modules/webpack/bin/webpack.js", "--mode", "development", "--watch-stdin",
+  watchers: <%= if webpack do %>[node: ["node_modules/webpack/bin/webpack.js", "--mode", "development", "--watch-stdin", "--colors",
                                         cd: Path.expand("../assets", __DIR__)]]<% else %>[]<% end %>
 
 # ## SSL Support
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 05e8338ed..9165f1c2b 100644
--- a/installer/templates/phx_umbrella/apps/app_name_web/mix.exs
+++ b/installer/templates/phx_umbrella/apps/app_name_web/mix.exs
@@ -54,6 +54,6 @@ defmodule <%= web_namespace %>.MixProject do
   #
   # See the documentation for `Mix` for more info on aliases.
   defp aliases do
-    [<%= if ecto do %>"test": ["ecto.create --quiet", "ecto.migrate", "test"]<% end %>]
+    [<%= if ecto do %>test: ["ecto.create --quiet", "ecto.migrate", "test"]<% end %>]
   end
 end
diff --git a/installer/templates/phx_web/templates/layout/app.html.eex b/installer/templates/phx_web/templates/layout/app.html.eex
index d9bc67994..b28aabe0b 100644
--- a/installer/templates/phx_web/templates/layout/app.html.eex
+++ b/installer/templates/phx_web/templates/layout/app.html.eex
@@ -12,7 +12,7 @@
       <section class="container">
         <nav role="navigation">
           <ul>
-            <li><a href="http://www.phoenixframework.org/docs">Get Started</a></li>
+            <li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
           </ul>
         </nav>
         <a href="http://phoenixframework.org/" class="phx-logo">
diff --git a/lib/phoenix/endpoint.ex b/lib/phoenix/endpoint.ex
index c549e82d9..b173d2cd4 100644
--- a/lib/phoenix/endpoint.ex
+++ b/lib/phoenix/endpoint.ex
@@ -331,7 +331,7 @@ defmodule Phoenix.Endpoint do
 
   By default, Phoenix instruments the following events:
 
-    * `:phoenix_controller_call` - it's the whole controller pipeline.
+    * `:phoenix_controller_call` - the entire controller pipeline.
       The `%Plug.Conn{}` is passed as runtime metadata.
     * `:phoenix_controller_render` - the rendering of a view from a
       controller. The map of runtime metadata passed to instrumentation
@@ -339,6 +339,11 @@ defmodule Phoenix.Endpoint do
       the `:template` key - for the name of the template, e.g.,
       `"index.html"`, the `:format` key - for the format of the template, and
       the `:conn` key - containing the `%Plug.Conn{}`.
+    * `:phoenix_error_render` - the rendering of an error view when an exception,
+      throw, or exit is caught. The map of runtime metadata contains the `:status`
+      key of the error's HTTP status code, the `:conn` key containg the
+      `%Plug.Conn{}`, as well as the `:kind`, `:reason`, and `:stacktrace` of
+      the caught error.
     * `:phoenix_channel_join` - the joining of a channel. The `%Phoenix.Socket{}`
       and join params are passed as runtime metadata via `:socket` and `:params`.
     * `:phoenix_channel_receive` - the receipt of an incoming message over a
diff --git a/lib/phoenix/presence.ex b/lib/phoenix/presence.ex
index 61f9cd1b1..3dba25dd5 100644
--- a/lib/phoenix/presence.ex
+++ b/lib/phoenix/presence.ex
@@ -45,7 +45,7 @@ defmodule Phoenix.Presence do
         def handle_info(:after_join, socket) do
           push(socket, "presence_state", Presence.list(socket))
           {:ok, _} = Presence.track(socket, socket.assigns.user_id, %{
-            online_at: inspect(System.system_time(:seconds))
+            online_at: inspect(System.system_time(:second))
           })
           {:noreply, socket}
         end
diff --git a/lib/phoenix/token.ex b/lib/phoenix/token.ex
index 078954a21..a8d2a07c1 100644
--- a/lib/phoenix/token.ex
+++ b/lib/phoenix/token.ex
@@ -103,7 +103,7 @@ defmodule Phoenix.Token do
     * `:key_digest` - option passed to `Plug.Crypto.KeyGenerator`
       when generating the encryption and signing keys. Defaults to `:sha256`
     * `:signed_at` - set the timestamp of the token in seconds.
-      Defaults to `System.system_time(:seconds)`
+      Defaults to `System.system_time(:second)`
   """
   def sign(context, salt, data, opts \\ []) when is_binary(salt) do
     {signed_at_seconds, key_opts} = Keyword.pop(opts, :signed_at)
@@ -233,5 +233,5 @@ defmodule Phoenix.Token do
 
   defp expired?(signed, max_age_secs), do: (signed + trunc(max_age_secs * 1000)) < now_ms()
 
-  defp now_ms, do: System.system_time(:milliseconds)
+  defp now_ms, do: System.system_time(:millisecond)
 end
diff --git a/lib/phoenix/transports/long_poll.ex b/lib/phoenix/transports/long_poll.ex
index ec8a6ed91..be7e0d0f7 100644
--- a/lib/phoenix/transports/long_poll.ex
+++ b/lib/phoenix/transports/long_poll.ex
@@ -98,7 +98,7 @@ defmodule Phoenix.Transports.LongPoll do
     priv_topic =
       "phx:lp:"
       <> Base.encode64(:crypto.strong_rand_bytes(16))
-      <> (System.system_time(:milliseconds) |> Integer.to_string)
+      <> (System.system_time(:millisecond) |> Integer.to_string)
 
     arg = {endpoint, handler, opts, conn.params, priv_topic}
 
diff --git a/lib/phoenix/transports/long_poll_server.ex b/lib/phoenix/transports/long_poll_server.ex
index 3425fcad8..d01b8841c 100644
--- a/lib/phoenix/transports/long_poll_server.ex
+++ b/lib/phoenix/transports/long_poll_server.ex
@@ -145,7 +145,7 @@ defmodule Phoenix.Transports.LongPoll.Server do
     end
   end
 
-  defp now_ms, do: System.system_time(:milliseconds)
+  defp now_ms, do: System.system_time(:millisecond)
 
   defp schedule_inactive_shutdown(window_ms) do
     Process.send_after(self(), :shutdown_if_inactive, window_ms)
diff --git a/lib/phoenix/view.ex b/lib/phoenix/view.ex
index 8d181a493..c947ac923 100644
--- a/lib/phoenix/view.ex
+++ b/lib/phoenix/view.ex
@@ -10,18 +10,26 @@ defmodule Phoenix.View do
 
   ## Examples
 
-  Phoenix defines the view template at `lib/web/web.ex`:
+  Phoenix defines the view template at `lib/your_app_web.ex`:
 
       defmodule YourAppWeb do
+        # ...
+
         def view do
           quote do
-            use Phoenix.View, root: "lib/web/templates"
+            use Phoenix.View, root: "lib/your_app_web/templates", namespace: "web"
+            
+            # Import convenience functions from controllers
+            import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1]
 
-            # Import common functionality
-            import YourApp.Router.Helpers
-
-            # Use Phoenix.HTML to import all HTML functions (forms, tags, etc)
+            # Use all HTML functionality (forms, tags, etc)
             use Phoenix.HTML
+          
+            import YourAppWeb.ErrorHelpers
+            import YourAppWeb.Gettext
+
+            # Alias the Helpers module as Routes
+            alias  YourAppWeb.Router.Helpers, as: Routes
           end
         end
 
@@ -34,11 +42,11 @@ defmodule Phoenix.View do
         use YourAppWeb, :view
       end
 
-  Because we have defined the template root to be "lib/web/templates", `Phoenix.View`
-  will automatically load all templates at "web/templates/user" and include them
+  Because we have defined the template root to be "lib/your_app_web/templates", `Phoenix.View`
+  will automatically load all templates at "your_app_web/templates/user" and include them
   in the `YourApp.UserView`. For example, imagine we have the template:
 
-      # web/templates/user/index.html.eex
+      # your_app_web/templates/user/index.html.eex
       Hello <%= @name %>
 
   The `.eex` extension maps to a template engine which tells Phoenix how
@@ -276,7 +284,7 @@ defmodule Phoenix.View do
 
   To use a precompiled template, create a `scripts.html.eex` file in the `templates`
   directory for the corresponding view you want it to render for. For example,
-  for the `UserView`, create the `scripts.html.eex` file at `web/templates/user/`.
+  for the `UserView`, create the `scripts.html.eex` file at `your_app_web/templates/user/`.
 
   ## Rendering based on controller template
 
diff --git a/mix.exs b/mix.exs
index 33efb055d..7475e901b 100644
--- a/mix.exs
+++ b/mix.exs
@@ -186,7 +186,7 @@ defmodule Phoenix.MixProject do
 
   defp aliases do
     [
-      "docs": ["docs", &generate_js_docs/1]
+      docs: ["docs", &generate_js_docs/1]
     ]
   end
 
diff --git a/priv/templates/phx.gen.presence/presence.ex b/priv/templates/phx.gen.presence/presence.ex
index b100c0b53..08af4c6bb 100644
--- a/priv/templates/phx.gen.presence/presence.ex
+++ b/priv/templates/phx.gen.presence/presence.ex
@@ -21,7 +21,7 @@ defmodule <%= module %> do
         def handle_info(:after_join, socket) do
           push(socket, "presence_state", Presence.list(socket))
           {:ok, _} = Presence.track(socket, socket.assigns.user_id, %{
-            online_at: inspect(System.system_time(:seconds))
+            online_at: inspect(System.system_time(:second))
           })
           {:noreply, socket}
         end


Test patch:
diff --git a/guides/testing/testing_controllers.md b/guides/testing/testing_controllers.md
index 405732959..02765bf05 100644
--- a/guides/testing/testing_controllers.md
+++ b/guides/testing/testing_controllers.md
@@ -136,7 +136,7 @@ defmodule HelloWeb.UserControllerTest do
 
     response =
       conn
-      |> get(user_path(conn, :index))
+      |> get(Routes.user_path(conn, :index))
       |> json_response(200)
 
     expected = %{
@@ -267,7 +267,7 @@ test "Responds with user info if the user is found", %{conn: conn} do
 
   response =
     conn
-    |> get(user_path(conn, :show, user.id))
+    |> get(Routes.user_path(conn, :show, user.id))
     |> json_response(200)
 
   expected = %{"data" => %{"email" => user.email, "name" => user.name}}
@@ -302,7 +302,7 @@ describe "show/2" do
 
     response =
       conn
-      |> get(user_path(conn, :show, user.id))
+      |> get(Routes.user_path(conn, :show, user.id))
       |> json_response(200)
 
     expected = %{"data" => %{"email" => user.email, "name" => user.name}}
@@ -324,7 +324,7 @@ Finally, let's change our `index/2` test to also use the new `create_user` funct
 
       response =
         conn
-        |> get(user_path(conn, :index))
+        |> get(Routes.user_path(conn, :index))
         |> json_response(200)
 
       expected = %{"data" => [%{"name" => user.name, "email" => user.email}]}
@@ -393,7 +393,7 @@ Walking through our TDD steps, we add a test that supplies a non-existent user i
 
 ```elixir
 test "Responds with a message indicating user not found", %{conn:  conn} do
-  conn = get(conn, user_path(conn, :show, -1))
+  conn = get(conn, Routes.user_path(conn, :show, -1))
 
   assert text_response(conn, 404) =~ "User not found"
 end
diff --git a/test/phoenix/token_test.exs b/test/phoenix/token_test.exs
index 0296124f5..e2b694598 100644
--- a/test/phoenix/token_test.exs
+++ b/test/phoenix/token_test.exs
@@ -60,7 +60,7 @@ defmodule Phoenix.TokenTest do
 
   test "supports signed_at in seconds" do
     seconds_in_day = 24*60*60
-    day_ago_seconds = System.system_time(:seconds) - seconds_in_day
+    day_ago_seconds = System.system_time(:second) - seconds_in_day
     token = Token.sign(conn(), "id", 1, signed_at: day_ago_seconds)
     assert Token.verify(conn(), "id", token, max_age: seconds_in_day + 1) == {:ok, 1}
     assert Token.verify(conn(), "id", token, max_age: seconds_in_day - 1) == {:error, :expired}