Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Phoenix 1.7 Controller.put_layout @spec does not allow 1.6 usage #5320

Closed
adamu opened this issue Mar 2, 2023 · 8 comments
Closed

Phoenix 1.7 Controller.put_layout @spec does not allow 1.6 usage #5320

adamu opened this issue Mar 2, 2023 · 8 comments

Comments

@adamu
Copy link
Contributor

adamu commented Mar 2, 2023

I have upgraded from Phoenix 1.6 to Phoenix 1.7 with minimal code changes, but I am having issues due to the the non-backwards compatible @spec change to put_layout:

@spec put_layout(Plug.Conn.t(), [{format :: atom, layout}]) :: Plug.Conn.t()
def put_layout(%Plug.Conn{state: state} = conn, layout) do

Although put_layout still accepts the 1.6 usage, the @spec does not. As a result, this line:

  plug :put_layout, {ExampleWeb.LayoutView, "app.html"}

Fails dialyzer checks with the following error, even though the code works.

lib/example_web/controllers/page_controller.ex:1:call
The function call will not succeed.

Phoenix.Controller.put_layout(
  _ :: %Plug.Conn{
    ...
  },
  {ExampleWeb.LayoutView, <<97, 112, 112, 46, 104, 116, 109, 108>>}
)

breaks the contract
(Plug.Conn.t(), [{format :: atom(), layout()}]) :: Plug.Conn.t()

Is this intentional, or could the | layout be restored to allow the @spec to match the behaviour?

@josevalim
Copy link
Member

Intentional. Consider it an early deprecation warning powered by Dialyzer. :)

@edds
Copy link

edds commented Mar 15, 2023

Unless I'm missing something does this change means anyone that uses Dialyzer can no longer use Phoenix.View as you can no longer set layouts to be used? This feels like a massive breaking change which didn't even get mentioned in the release notes.

@josevalim
Copy link
Member

josevalim commented Mar 15, 2023

You can use Phoenix.View and you can still set layouts. That's not the problem here. The old style still works and, if you want to avoid the Dialyzer warning (which does not stop the code from executing), it is a matter of replacing this:

plug :put_layout, {ExampleWeb.LayoutView, "app.html"}

by this:

plug :put_layout, html: {ExampleWeb.LayoutView, "app.html"}

@adamu
Copy link
Contributor Author

adamu commented Mar 15, 2023

plug :put_layout, html: {ExampleWeb.LayoutView, "app.html"}

This was not a drop-in replacement for me, as it seems to require that you are also using the new-style layouts:

put_layout and put_root_layout expects an module and template per format, such as:

    html: {MyView, :app}

Got:

    {ExampleWeb.LayoutView, "custom.html"}

If I use the new atom syntax html: {ExampleWeb.LayoutView, :custom}, there are no errors, but the custom layout is not used, it uses the app layout instead.

However, the old syntax works fine.


What I did was write a hack to hide it from dialyzer, until we have time to migrate properly:

  @spec put_layout_workaround(Plug.Conn.t(), {atom(), String.t()}) :: Plug.Conn.t()
  def put_layout_workaround(conn, arg) do
    # credo:disable-for-next-line Credo.Check.Refactor.Apply
    apply(Phoenix.Controller, :put_layout, [conn, arg])
  end

Then

plug :put_layout_workaround, {ExampleWeb.LayoutView, "custom.html"}

@edds
Copy link

edds commented Mar 15, 2023

@adamu yeah I got the same exception trying the code @josevalim is suggesting. Your hack to get around dialyzer looks like it will be necessary as the new style does seem to require you to migrate your app which we just don't have time for in one go and don't want to get left behind.

@josevalim
Copy link
Member

Hrm, this is not supposed to happen. Can you folks please provide a custom app that reproduces the error? Then I will take a look at it immediately. :)

PS: @adamu my kid was very happy to see a Minecraft something (your avatar I believe) at his dad work computer :D

@adamu
Copy link
Contributor Author

adamu commented Mar 16, 2023

Haha, I made that avatar way back in 2012 or so. It's been a while since I actually played :)

I've made a reproduction of the issue in a dummy project here:

https://github.com/adamu/put_layout_repro/blob/c331d0addc38dad9493c152826f6a07a8d3f1ce8/lib/put_layout_repro_web/router.ex#L9-L16

    # ---------------------------------------------------------------
    # Working
    plug :put_layout, {PutLayoutReproWeb.LayoutView, "custom.html"}
    # Fails to compile
    # plug :put_layout, html: {PutLayoutReproWeb.LayoutView, "custom.html"}
    # Uses App layout
    # plug :put_layout, html: {PutLayoutReproWeb.LayoutView, :custom}
    # ---------------------------------------------------------------

@josevalim josevalim reopened this Mar 16, 2023
@josevalim
Copy link
Member

Thank you so much! ❤️ I pushed a warning that hopefully clarifies the situation. TL;DR: change your :controller to do:

use Phoenix.Controller, layouts: [html: {PutLayoutReproWeb.LayoutView, :app}]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants