From this tutorial, I have some elegant:
get("/old-path", Redirector, to: "/new-path")
get("/old-path/:id", Redirector, to: "/new-path?object=:id")
in my router.ex
.
But I now have a more complex case, which requires my redirection to be dynamic. I wanted to go for:
get("/other-old-path", Redirector, to: fn conn, options -> "/whatever-path" end)
And wrote on my Redirector
module:
to = if is_function(to), do: to.(conn, Keyword.drop(options, :to)), else: to
I was pretty confident with my code, but when I tried to execute it, I received the following error:
== Compilation error in file web/router.ex ==
** (ArgumentError) cannot escape #Function<5.71083082/2 in :elixir_compiler_10.__MODULE__/1>. The supported values are: lists, tuples, maps, atoms, numbers, bitstrings, PIDs and remote functions in the format &Mod.fun/arity
(elixir) src/elixir_quote.erl:122: :elixir_quote.argument_error/1
(elixir) src/elixir_quote.erl:259: :elixir_quote.do_quote/3
(elixir) src/elixir_quote.erl:310: :elixir_quote.do_escape/3
(phoenix) lib/phoenix/router/route.ex:136: Phoenix.Router.Route.build_dispatch/1
(phoenix) lib/phoenix/router/route.ex:73: Phoenix.Router.Route.exprs/1
(phoenix) lib/phoenix/router.ex:334: anonymous fn/1 in Phoenix.Router."MACRO-__before_compile__"/2
(elixir) lib/enum.ex:1327: Enum."-map/2-lists^map/1-0-"/2
(elixir) lib/enum.ex:1327: Enum."-map/2-lists^map/1-0-"/2
(phoenix) expanding macro: Phoenix.Router.__before_compile__/1
web/router.ex:1: MyApp.Router (module)
(elixir) lib/kernel/parallel_compiler.ex:208: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6
Googling it sent me to this page which mentions I can't do what I want to do. I read this has to do with quoted expressions so I tried to understand how this can be useful, but still don't.
I tried to pass an anonymous function in a keyword list in a parameter of a function in the console and it worked.
I'm guessing it breaks here because the behavior of get
is more meta.
Anyway, I'm sure I'll get more comfortable along working deeper with Elixir, and one day I'll clearly understand why it did not work (explanations welcome of course!), but by then, how can I write what I want to do?
It doesn't feel like I am doing something elixir-difficult but it apparently is...
Cheers
EDIT: thanks for reply.
I did what you suggested @justin-wood but it doesn't work:
get("/other-old-path", Redirector, to: &MyApp.Router.do_redirect/2)
and at the bottom of the file
def do_redirect(conn, options), do: "/youpi"
But I get a hideous error:
== Compilation error in file web/router.ex ==
** (FunctionClauseError) no function clause matching in :v3_core.pattern/2
The following arguments were given to :v3_core.pattern/2:
# 1
{:fun, 0, {:function, {:atom, 0, Vae.Router}, {:atom, 0, :do_redirect}, {:integer, 0, 2}}}
# 2
{:core, 2, 0, {:redirector_path, 2}, ... [more uglyness]
** (FunctionClauseError) no function clause matching in :v3_core.pattern/2
is a compiler bug. Please open up a bug report with a minimal case, including the Elixir and Erlang/OTP versions! Thanks. – José Valim