Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog for v1.9

Nothing, so far.
## v1.9.0-dev

### Enhancements

* [Phoenix.Router] Add `use Phoenix.Router, group_by: :verb` to group routes per verb during compilation. This can improve compilation times for large routers with no performance cost at runtime. When enabled, all `match :*` and `forward` routes must be defined at the end of the router, otherwise compilation fails with a list of violations
Comment thread
josevalim marked this conversation as resolved.
Outdated

## v1.8

Expand Down
2 changes: 2 additions & 0 deletions guides/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,8 @@ end

This means that all routes starting with `/jobs` will be sent to the `BackgroundJob.Plug` module. Inside the plug, you can match on subroutes, such as `/pending` and `/active` that shows the status of certain jobs.

Since forwards match all HTTP methods under their path, keep them at the end of your router, after your application routes. The same applies to any `match :*` routes. This is required when a router is configured with `group_by: :verb`.

Comment thread
josevalim marked this conversation as resolved.
Outdated
We can even mix the [`forward/4`](`Phoenix.Router.forward/4`) macro with pipelines. If we wanted to ensure that the user was authenticated and was an administrator in order to see the jobs page, we could use the following in our router.

```elixir
Expand Down
34 changes: 34 additions & 0 deletions integration_test/test/support/code_generator_case.ex
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,40 @@ defmodule Phoenix.Integration.CodeGeneratorCase do

def inject_before_final_end(code, code_to_inject)
when is_binary(code) and is_binary(code_to_inject) do
inject_before_dev_routes_scope(code, code_to_inject) ||
inject_before_final_end_fallback(code, code_to_inject)
end

defp inject_before_dev_routes_scope(code, code_to_inject) do
case split_before_dev_routes(String.split(code, "\n"), []) do
{before_dev_routes, dev_routes} ->
join_injected(before_dev_routes, code_to_inject, dev_routes)

_ ->
nil
end
end

defp split_before_dev_routes([line | rest], acc) do
if String.contains?(line, "if Application.compile_env") and
String.contains?(line, ":dev_routes") do
{dev_route_comments, before_dev_routes} =
Enum.split_while(acc, &(String.trim_leading(&1) |> String.starts_with?("#")))

{Enum.reverse(before_dev_routes), Enum.reverse(dev_route_comments, [line | rest])}
else
split_before_dev_routes(rest, [line | acc])
end
end

defp split_before_dev_routes([], _acc), do: nil

defp join_injected(before_dev_routes, code_to_inject, dev_routes) do
code_to_inject = code_to_inject |> String.trim("\n") |> String.split("\n")
Enum.join(before_dev_routes ++ code_to_inject ++ [""] ++ dev_routes, "\n")
end

defp inject_before_final_end_fallback(code, code_to_inject) do
code
|> String.trim_trailing()
|> String.trim_trailing("end")
Expand Down
48 changes: 40 additions & 8 deletions lib/mix/tasks/phx.gen.auth/injector.ex
Original file line number Diff line number Diff line change
Expand Up @@ -268,17 +268,49 @@ defmodule Mix.Tasks.Phx.Gen.Auth.Injector do
if String.contains?(code, code_to_inject) do
:already_injected
else
new_code =
code
|> String.trim_trailing()
|> String.trim_trailing("end")
|> Kernel.<>(code_to_inject)
|> Kernel.<>("end\n")

{:ok, new_code}
{:ok,
inject_before_dev_routes_scope(code, code_to_inject) ||
inject_before_final_end_fallback(code, code_to_inject)}
end
end

defp inject_before_dev_routes_scope(code, code_to_inject) do
case split_before_dev_routes(String.split(code, "\n"), []) do
{before_dev_routes, dev_routes} ->
join_injected(before_dev_routes, code_to_inject, dev_routes)

_ ->
nil
end
end

defp split_before_dev_routes([line | rest], acc) do
if String.contains?(line, "if Application.compile_env") and
String.contains?(line, ":dev_routes") do
{dev_route_comments, before_dev_routes} =
Enum.split_while(acc, &(String.trim_leading(&1) |> String.starts_with?("#")))

{Enum.reverse(before_dev_routes), Enum.reverse(dev_route_comments, [line | rest])}
else
split_before_dev_routes(rest, [line | acc])
end
end

defp split_before_dev_routes([], _acc), do: nil

defp join_injected(before_dev_routes, code_to_inject, dev_routes) do
code_to_inject = code_to_inject |> String.trim("\n") |> String.split("\n")
Enum.join(before_dev_routes ++ code_to_inject ++ [""] ++ dev_routes, "\n")
end

defp inject_before_final_end_fallback(code, code_to_inject) do
code
|> String.trim_trailing()
|> String.trim_trailing("end")
|> Kernel.<>(code_to_inject)
|> Kernel.<>("end\n")
end

@spec ensure_not_already_injected(String.t(), String.t()) :: :ok | :already_injected
defp ensure_not_already_injected(file, inject) do
if String.contains?(file, inject) do
Expand Down
Loading
Loading