zazaian

zazaian

Restructuring Phoenix 1.3-rc apps for 1.3.1, 1.3.2, 1.3.x

I recently generated the boilerplate for a new mix app using the Phoenix 1.3.1 phx.new generator and realized that the structure of the web directory and namespace have changed after 1.3-rc, which was structured differently than the 1.3.x release variants, namely 1.3.0, 1.3.1, and 1.3.2. Because I already had a production Phoenix app based on the 1.3-rc structure (upgraded from 1.2) running under the same umbrella, I wanted to update that app to match the structure of the formally released 1.3.x variants.

Fundamentally these changes are very simple:

  • The MyApp.Web module becomes MyAppWeb.
  • The top-level MyApp namespace no longer contains the OTP application configuration for the app. This privilege is now delegated to MyApp.Application.
  • Domain and web libraries are split apart in /lib as /lib/myapp and /lib/myapp_web.
  • Tests for myapp_web are moved into /test/myapp_web.

This might not sound like much, but many files will be affected and/or relocated. Here’s a high-level overview of my process for making these updates:

  • Use sed to update all references to the MyApp.Web module to MyAppWeb. Be careful not to include your git repo files when using sed destructively. I just grepped for the files containing MyApp.Web and sed-replaced them in batches per-directory with:
sed -i -e 's/MyApp\.Web/MyAppWeb/g' *.ex *.exs
  • Move your former /lib/myapp/web directory one level down, into /lib:
git mv lib/myapp/web/ lib/myapp_web
  • Move endpoint.ex from /lib/myapp to /lib/myapp_web:
git mv lib/myapp/endpoint.ex lib/myapp_web/endpoint.ex`
  • Move web.ex into /lib as the top-level MyAppWeb module definition:
git mv lib/myapp_web/web.ex lib/myapp_web.ex
  • Update the template root path in the new /lib/myapp_web.ex file to reflect the new directory structure:
# original 1.3-rc:
  def view do
    quote do
      use Phoenix.View, root: "lib/myapp/web/templates", pattern: "**/*",

# updated 1.3.x (1.3.0, 1.3.1, and 1.3.2):
  def view do
    quote do
      use Phoenix.View, root: "lib/myapp_web/templates", pattern: "**/*",
  • Move the application definition at /lib/myapp_web/myapp.ex to /lib/myapp/application.ex:
git mv lib/myapp_web/myapp.ex lib/myapp/application.ex
  • Update module name in the application file from MyApp to MyApp.Application:
# /lib/myapp/application.ex

# original 1.3-rc:
defmodule MyApp do
  use Application
  # ...
end

# updated for 1.3.x (1.3.0, 1.3.1 or 1.3.2):
defmodule MyApp.Application do
   use Application
   # ...
end
  • Update the application module name in mix.exs:
# /mix.exs

# original 1.3-rc:
  def application do
    [ mod: {MyApp, []},

# updated for 1.3.x (1.3.0, 1.3.1 or 1.3.2)
  def application do
    [ mod: {MyApp.Application, []},
  • Generate a new top-level module definition file at /lib/myapp.ex:
# This module was previous populated with the app code that we just extracted
# into MyApp.Application, so there isn't necessarily any additional code here unless
# you've added non-application code to the module:

# /lib/myapp.ex

defmodule MyApp do
end 
  • Update the live-reload patterns in your dev env config to reflect the changes. For example:
       # /config/dev.exs

       # original 1.3-rc
      ~r{lib/myapp/web/views/.*(ex)$},
      ~r{lib/myapp/web/templates/.*(eex|haml|slim|slime)$}

       # updated for 1.3.x (1.3.0, 1.3.1 or 1.3.2):
      ~r{lib/myapp_web/views/.*(ex)$},
      ~r{lib/myapp_web/templates/.*(eex|haml|slim|slime)$}
  • Move your web-related tests into /test/myapp_web. I previously had the tests for my views and controllers at /test/views and /test/controllers respectively, so I just moved them into a new myapp_web directory:
mkdir test/myapp_web
git mv test/views test/myapp_web
git mv test/controllers test/myapp_web

Finally I just updated the Phoenix version reference in mix.exs to 1.3.1 and did mix do: deps.get, compile, test, and everything worked correctly. I then took step further and updated my Phoenix dependencies to 1.3.2 and had no issues.

I believe this should be all of the necessary steps, but if I’ve missed anything, or any of this looks incorrect, please let me know and I’ll update the guide here.

Thanks,
Mike

Note: This post originally stated that this structual difference was a discrepancy between 1.3.0 and 1.3.1, when in fact it was a change made between the releases of 1.3-rc and 1.3.0. Thanks to @chrismccord for offering this clarification.

Most Liked

chrismccord

chrismccord

Creator of Phoenix

To be clear, we did not change any structure from 1.3.0 - 1.3.2. I believe you were running an early 1.3 RC version which used the App.Web namespace, and we moved to AppWeb before final release. I’ve updated the title accordingly :slight_smile:

zazaian

zazaian

Hey there Chris - thanks for the response here. That indeed was the case. I didn’t realize this structure had changed between 1.3-rc and 1.3.0. The clarification is much appreciated. I just quickly revised the references in the examples, but I’ll go through the tutorial tomorrow and update the rest of the language to better reflect this distinction.

Where Next?

Popular in Guides/Tuts Top

sergio
Hey there, we’re going to walk through deploying a Phoenix app to a DigitalOcean droplet, manually - no tools no nothing. Just straight u...
New
tfwright
I thought I’d share a small project I’m working on to gain some familiarty with LiveView in a Phoenix app. Github Repo Deployment It’s...
New
Logan
Here is an example of a Mix application that utilizes Cowboy to handle websocket connections. If anyone has an idea about making this wor...
New
njwest
Greetings: I just wrote a step-by-step guide on building a Phoenix 1.3 JWT Auth API with Guardian JWTs and Comeonin password hashing. I ...
New
marcelo
I wrote a small article on how to use current_user with coherence on Phoenix. There are already a couple of blogposts about it but I thin...
New
drapermd
So here is the code I came up with to generically generate an array param that will be stored on a jsonb property in ecto. It only handl...
New
cheerfulstoic
I spent quite a bit of time trying to find a good configuration to build / test my Elixir app in CircleCI and then push an image to Docke...
New
redfloyd
Greetings fellow alchemists ! I have started to write an open-source interpreter in Elixir (https://github.com/nicolasdilley/dwarf-inter...
New
dogweather
I just finished a long process of configuring and debugging a Docker Compose-based dev environment. Several late-night hours! I think I’v...
New
fmcgeough
pipe into case? I use that fairly frequently…unless I’m misunderstanding what you’re wanting…could be… its still very early… str = "Hell...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement