Repository: phoenixframework/phoenix (elixir)

Issue:
Using router helpers during compilation time throws an ets lookup error
### Environment

* Elixir version (elixir -v): 1.6.0 (compiled with OTP 20)
* Phoenix version (mix deps):  1.3.2
* Operating system: OS X

### Expected behavior
It's possible to pass a `path` as an argument to the plug

### Actual behavior
Using router helper during compilation throws an ETS lookup error

controller:

```
defmodule PathCacheWeb.PageController do
  use PathCacheWeb, :controller
  plug PathCacheWeb.Plug.DummyPlug, [redirect_path: page_path(PathCacheWeb.Endpoint, :index)]
```

backtrace: 
```
= Compilation error in file lib/path_cache_web/controllers/page_controller.ex ==
** (ArgumentError) argument error
    (stdlib) :ets.lookup(PathCacheWeb.Endpoint, :__phoenix_path__)
    (phoenix) lib/phoenix/config.ex:45: Phoenix.Config.cache/3
    lib/phoenix/endpoint.ex:643: PathCacheWeb.Endpoint.path/1
    lib/path_cache_web/controllers/page_controller.ex:6: (module)
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:198: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6
```

I suspect that it’s because of the `:ets.lookup` tries to access non-existing table which is being created only in the runtime https://github.com/phoenixframework/phoenix/blob/master/lib/phoenix/config.ex#L102

Sample repository https://github.com/lessless/path_cache_bug

P.S.  simpler way to reproduce is just to add a module attribute

```
defmodule PathCacheWeb.PageController do
  use PathCacheWeb, :controller
  @lolo page_path(PathCacheWeb.Endpoint, :index)
```



Pull request:
Helpful error message when accessing endpoint config at compile time
Fixes #2841

Patch:
diff --git a/guides/plug.md b/guides/plug.md
index abcab2003..0403c2360 100644
--- a/guides/plug.md
+++ b/guides/plug.md
@@ -113,7 +113,7 @@ defmodule HelloWeb.Router do
   ...
 ```
 
-In the [`init/1`] callback, we pass a default locale to use if none is present in the params. We also use pattern matching to define multiple [`call/2`] function heads to validate the locale in the params, and fall back to `"en"` if there is no match.
+In the [`init/1`] callback, we pass a default locale to use if none is present in the params. We also use pattern matching to define multiple [`call/2`] function heads to validate the locale in the params, and fall back to `"en"` if there is no match. The [`assign/3`] is a part of the `Plug.Conn` module and it's how we store values in the `conn` data structure.
 
 To see the assign in action, go to the layout in `lib/hello_web/templates/layout/app.html.eex` and add the following close to the main container:
 
diff --git a/lib/phoenix/config.ex b/lib/phoenix/config.ex
index 685755b82..6927f91bb 100644
--- a/lib/phoenix/config.ex
+++ b/lib/phoenix/config.ex
@@ -46,7 +46,18 @@ defmodule Phoenix.Config do
   """
   @spec cache(module, term, (module -> {:cache | :nocache, term})) :: term
   def cache(module, key, fun) do
-    case :ets.lookup(module, key) do
+    try do
+      :ets.lookup(module, key)
+    rescue
+      e ->
+        case :ets.info(module) do
+          :undefined ->
+            raise "could not find ets table for endpoint #{inspect(module)}. Make sure your endpoint is started and note you cannot access endpoint functions at compile-time."
+
+          _ ->
+            reraise e, __STACKTRACE__
+        end
+    else
       [{^key, :cache, val}] ->
         val
 
diff --git a/priv/templates/phx.gen.html/show.html.eex b/priv/templates/phx.gen.html/show.html.eex
index c19a2c955..469fc4a13 100644
--- a/priv/templates/phx.gen.html/show.html.eex
+++ b/priv/templates/phx.gen.html/show.html.eex
@@ -9,5 +9,5 @@
 <% end %>
 </ul>
 
-<span><%%= link "Edit", to: Routes.<%= schema.route_helper %>_path(@conn, :edit, @<%= schema.singular %>) %></span>
+<span><%%= link "Edit", to: Routes.<%= schema.route_helper %>_path(@conn, :edit, @<%= schema.singular %>) %></span> |
 <span><%%= link "Back", to: Routes.<%= schema.route_helper %>_path(@conn, :index) %></span>
diff --git a/priv/templates/phx.gen.live/show.html.leex b/priv/templates/phx.gen.live/show.html.leex
index 236f80e45..9de080b77 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.route_helper %>_show_path(@socket, :edit, @<%= schema.singular %>), class: "button" %></span>
+<span><%%= live_patch "Edit", to: Routes.<%= schema.route_helper %>_show_path(@socket, :edit, @<%= schema.singular %>), class: "button" %></span> |
 <span><%%= live_redirect "Back", to: Routes.<%= schema.route_helper %>_index_path(@socket, :index) %></span>


Test patch:
diff --git a/test/phoenix/config_test.exs b/test/phoenix/config_test.exs
index ad69c5d5a..6c0156d49 100644
--- a/test/phoenix/config_test.exs
+++ b/test/phoenix/config_test.exs
@@ -22,6 +22,12 @@ defmodule Phoenix.ConfigTest do
     assert :ets.lookup(meta.test, :custom)  == [custom: true]
   end
 
+  test "raises with warning about compile time when table not started" do
+    assert_raise RuntimeError,
+                 "could not find ets table for endpoint Fooz. Make sure your endpoint is started and note you cannot access endpoint functions at compile-time.",
+                 fn -> cache(Fooz, :foo, fn _ -> {:nocache, :bar} end) end
+  end
+
   test "can change configuration", meta do
     {:ok, pid} = start_link({meta.test, @all, @defaults, []})
     ref = Process.monitor(pid)