Repository: phoenixframework/phoenix
Pull request #3310 (2019-03-10 06:16:08)

Add ability to expand scoped alias in current router scope


Patch:
diff --git a/lib/phoenix/router.ex b/lib/phoenix/router.ex
index af260cd73..860065e5b 100644
--- a/lib/phoenix/router.ex
+++ b/lib/phoenix/router.ex
@@ -671,7 +671,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 +747,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(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..d0b9bdda0 100644
--- a/lib/phoenix/router/scope.ex
+++ b/lib/phoenix/router/scope.ex
@@ -23,9 +23,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
 
@@ -132,7 +133,10 @@ 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
+  @doc """
+  Expands the alias in the current router scope.
+  """
+  def expand_alias(module, alias) do
     if inside_scope?(module) do
       module
       |> get_stack()
@@ -142,9 +146,16 @@ defmodule Phoenix.Router.Scope do
     end
   end
 
-  defp join(module, path, alias, as, private, assigns) do
+  defp join(module, path, alias, alias?, as, private, assigns) do
     stack = get_stack(module)
-    {join_path(stack, path), find_host(stack), join_alias(stack, alias),
+    joined_alias =
+      if alias? do
+        join_alias(stack, alias)
+      else
+        alias
+      end
+
+    {join_path(stack, path), find_host(stack), joined_alias,
      join_as(stack, as), join_pipe_through(stack), join_private(stack, private),
      join_assigns(stack, assigns)}
   end


Test patch:
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