Subscribe to access all episodes. View plans →

#153: Upgrading to Phoenix 1.7

Published November 14, 2022

phoenix 1.7.0-rc.0

Follow along with the episode starter on GitHub


It’s an exciting time because the first release of Phoenix 1.7 is out! Phoenix 1.7 has a lot of great features like Tailwind support, LiveView Auth generators, and Verified Routes. In this episode let’s see how we can upgrade an Elixir application from Phoenix 1.6 to 1.7. And as always, we’ll be following Chris McCord’s upgrade guide.

The application we’ll be upgrading is this one you’ve probably seen before, which is just a very basic Phoenix 1.6 application that lists some albums. Now while it’s not a hard requirement, it’s encouraged to upgrade to Elixir 1.14, which provides support for proper warnings for the new Phoenix.VerifiedRoutes feature as well as Phoenix LiveView 0.18’s new declarative assigns. Our example application here is already on Elixir 1.14 so we’re good to go.

$ elixir -v
Elixir 1.14.1 (compiled with Erlang/OTP 24)

Alright, let’s get started by opening our application’s Mixfile. We’ll update to {:phoenix, "~> 1.7.0-rc.0", override: true}, {:phoenix_live_view, "~> 0.18.3"}, and {:phoenix_live_dashboard, "~> 0.7.2"}. Then in the project function above we can remove the compilers line, which is no are longer necessary on Elixir v1.14 and up.

mix.exs

...
def project do
  [
    ...
    # compilers: [] ++ Mix.compilers(),
    ...
  ]
end

...

def deps do
  [
    {:phoenix, "~> 1.7.0-rc.0", override: true},
    {:phoenix_live_view, "~> 0.18.3"},
    {:phoenix_live_dashboard, "~> 0.7.2"},
    ...
  ]
end

...

With that update, let’s go to the command line and get our new dependencies.

$ mix deps.get
...
Upgraded:
  ecto 3.8.2 => 3.8.4
  jason 1.3.0 => 1.4.0
  mime 2.0.2 => 2.0.3
  phoenix 1.6.7 => 1.7.0-rc.0
  phoenix_live_dashboard 0.6.5 => 0.7.2 (minor)
  phoenix_live_view 0.17.9 => 0.18.3 (minor)
  plug 1.13.6 => 1.14.0
  plug_cowboy 2.5.2 => 2.6.0
  plug_crypto 1.2.2 => 1.2.3
New:
  phoenix_template 1.0.0
  websock 0.4.3
  websock_adapter 0.4.4

Then let’s open our .formatter.exs and update it to include the Phoenix.LiveView.HTMLFormatter plugin.

.formatter.exs

[
  ...
  plugins: [Phoenix.LiveView.HTMLFormatter]
]

With this release Phoenix.LiveView.Helpers has been soft deprecated. We’ll need to replace it with Phoenix.Component. Currently, we’re only using it in the teacher_web.ex module, so let’s open that and let’s find where it’s being used then we can replace it with import Phoenix.Component.

lib/teacher_web.ex

...
defp view_helpers do
  quote do
    ...
    import Phoenix.Component
    ...
  end
end
...

The live_title_tag helper has also been changed to be a function component, so let’s open our root.html.heex template and update it to use the <.live_title> function component instead.

Template path: lib/teacher_web/templates/layout/root.html.heex

...
<.live_title suffix=" · Phoenix Framework">
  <%= assigns[:page_title] || "Teacher" %>
</.live_title>
...

Great, with those changes let’s see if our app will start.

We’ll go to the command line and try to start the server and when we do we get an error - module Phoenix.View is not loaded and could not be found. This is because Phoenix 1.7 doesn’t use Phoenix.View, but if you still need to use it it’s been extracted to its own package. Let’s go to Hex and grab the phoenix_view package and add it to our Mixfile’s list of dependencies…

mix.exs

...
defp deps do
[
  ...
  {:phoenix_view, "~> 2.0"}
  ...
]
end
...

Then let’s go to the command line and get our new dependency.

$ mix deps.get
...
Upgraded:
  phoenix_view 1.1.2 => 2.0.2 (major)

Now let’s try to start the server again. It starts up, but we do get a deprecation warning letting us know that get_flash has been deprecated and we should update our app to use Phoenix.Flash.get(@flash, key).

$ mix phx.server
Compiling 1 file (.ex)
warning: Phoenix.Controller.get_flash/2 is deprecated. get_flash/2 is deprecated. Use Phoenix.Flash.get(@flash, key) instead
Invalid call found at 2 locations:
  lib/teacher_web/templates/layout/app.html.heex:2: TeacherWeb.LayoutView."app.html"/1
  lib/teacher_web/templates/layout/app.html.heex:3: TeacherWeb.LayoutView."app.html"/1

This is an easy enough fix, so let’s open our app.html.heex template and update the flash message to use the new Phoenix.Flash.get function.

Template path: lib/teacher_web/templates/layout/app.html.heex

...
<p class="alert alert-info" role="alert"><%= Phoenix.Flash.get(@flash, :info) %></p>
<p class="alert alert-danger" role="alert"><%= Phoenix.Flash.get(@flash, :error) %></p>
...

Great, now when we start our server the deprecation warnings are gone!

$ mix phx.server
...

And our app is working great! We’re able to use our app and everything seems to be working with the existing code.

One of the major new features of Phoenix 1.7 is verified routes. Verified routes use the sigil_p macro and allow paths and URLs throughout your application to be compile-time verified against your Phoenix router. Let’s update one route in our app to use it.

We’ll go to our page’s index.html.heex template and we’ll use the <.link> component and then before we were using the Routes helper to generate the route, we can now use the sigil ~p with the string for our route. Because these are compile-time verified against the routes in your router, you don’t have the maintenance issues that you normally would using hardcoded strings in your app.

Template path: lib/teacher_web/templates/page/index.html.heex

...
<.link href={~p"/albums"}>all albums</.link>
...

But with that update, if we go to the command line and try to start our server, we get an error - undefined function sigil_p.

$ mix phx.server
Compiling 1 file (.ex)

== Compilation error in file lib/teacher_web/views/page_view.ex ==
** (CompileError) lib/teacher_web/templates/page/index.html.heex:4: undefined function sigil_p/2 (expected TeacherWeb.PageView to define such a function or for it to be imported, but none are available)

This is because if we want to use Verified Routes in our application, we have a few more updates we need to make.

We’ll go back to our teacher_web.ex module and here we’ll copy over some of the changes from the upgrade guide. First, we’ll add the static_paths public function. Then we’ll update our controller to use a new verified_routes function that we’ll need to create and we’ll need to add it to the view_helpers as well. Then let’s create the verified_routes function - I’ll paste the body of the function from the upgrade guide. This will allow us to use verified routes in our views and controllers.

lib/teacher_web.ex

defmodule TeacherWeb do

def static_paths do
  ~w(assets fonts images favicon.ico robots.txt)
end

def controller do
  quote do
    ...
    unquote(verified_routes())
  end

end

...

defp view_helpers do
  quote do
    ...

    unquote(verified_routes())
  end

end

def verified_routes do
  quote do
    use Phoenix.VerifiedRoutes,
      endpoint: TeacherWeb.Endpoint,
      router: TeacherWeb.Router,
      statics: TeacherWeb.static_paths()
  end
end

...

end


Now we need to open our endpoint.ex and update Plug.Static to use the new TeacherWeb.static_paths() function we just created.

lib/app_web/endpoint.ex

...

plug Plug.Static,
  at: "/",
  from: :teacher,
  gzip: false,
  only: TeacherWeb.static_paths()

...

And finally, we’ll need to update the conn_case.ex module to use TeacherWeb, :verified_routes.

test/support/conn_case.ex

defmodule TeacherWeb.ConnCase do

  ...

  using do
    quote do
    ...

    use TeacherWeb, :verified_routes

    ...
    end

  end

  ...

end

With those changes let’s go back to the command line and since we updated our conn_case.ex module, we’ll want to make sure our tests still pass - great - they look good.

$ mix test
...................
Finished in 0.1 seconds (0.06s async, 0.06s sync)
19 tests, 0 failures

Now let’s see if we can start our app using the new verified route.

$ mix phx.server
...

Awesome - it starts up and our link works using Phoenix 1.7’s new verified routes. Our app is now upgraded to Phoenix 1.7.

© 2024 HEXMONSTER LLC