So far we have seen how to use the basic data types and coding principles of the Erlang VM via the Elixir language. Now we will go full circle and create a working web application using the Phoenix Web Framework.
Phoenix uses the MVC server-side pattern and is in fact the top layer of a multi-layer modular system encompassing Plug (the modular specification used for Routing, Controllers, etc.), Ecto (DB wrapper for MongoDB, MySQL, SQLite3, PostgreSQL, and MSSQL) and the HTTP server (Cowboy).
Phoenix's structure will seem familiar to Django for Python or Ruby on Rails. Both app performance and development speed were key factors in the design of Phoenix, and when combined with its real-time features, they give it powerful potential as a production-quality web-app framework.
Getting Started
Elixir is required, so please refer to the installation instructions at the beginning of this series.
We will also require Hex to get Phoenix working (to install dependencies). Here's the command to install Hex (if you have Hex already installed, it will upgrade Hex to the latest version):
If you have not yet familiarised yourself with the Elixir language, may I recommend you continue reading the first steps of this guide before going forward in this part.
Note that if you wish to read a short guide, you can also refer to the Learning Elixir and Erlang Guide that is provided by the Phoenix team.
Erlang
Note: By default, this is included in an Elixir installation.
To run Elixir, we need the Erlang virtual machine because Elixir code compiles to Erlang byte code.
If you're using a Debian-based system, you may need to explicitly install Erlang to get all the needed packages.
Phoenix
So now that we have Elixir and Erlang taken care of, you are ready to install the Mix archive.
A mix archive is just like a Zip file really, except that it contains an application as well as the compiled BEAM files and is tied to a specific version of the app.
The mix archive is what we will use to generate a new, base Phoenix application from which we can build our app!
Run the following in your terminal:
If the Phoenix Mix archive won't install properly with this command, we can download the package from the Phoenix archives, save it to the filesystem, and then run: mix archive.install /path/to/local/phoenix_new.ez.
Node
We will need node.js version 5 or greater, as Phoenix will use the brunch.io package to compile static assets such as css and js, which in turn uses npm.
Download Node.js from the download page. When selecting a package to download, it's important to note that Phoenix requires version 5.0.0 or greater.
Mac OS X users can also install Node.js via homebrew.
If you have any issues installing Node, refer to the official Phoenix help guide.
PostgreSQL
By default, Phoenix configures applications to use the relation db server PostgreSQL, but we can switch to MySQL by passing the --database mysql flag when creating a new application.
Going forward, as we work with Ecto models in this guide, we will use PostgreSQL and the Postgrex adapter.
So to follow along with the examples, you should install PostgreSQL. The PostgreSQL wiki has installation guides for a number of different operating systems.
Note that Postgrex is a direct Phoenix dependency, and it will be automatically installed along with the rest of our dependencies as we start our app.
The Default User
Phoenix assumes that our PostgreSQL database will have a postgres user account with the correct permissions and a password of "postgres". If that isn't how you want to set up, please see the instructions for the ecto.create mix task to customise the credentials.
Skeleton Install
If you only want the bare bones to get your phoenix app running, with no Ecto or Plug (no db or brunch.io), create your app with the following --no-brunch and --no-ecto flags:
Pre-Flight Check
By this point, you should have:
Elixir
Erlang (by default provided by Elixir installation)
Hex
Phoenix mix archive installed
Additionally, if you have opted for DB and static-asset support, you will also have PostgreSQL and Node.js >= 5.0.0, in which case you will now be ready to create your app.
Create Your App
You can run mix phoenix.new from any directory in order to bootstrap a Phoenix application.
For your new project, Phoenix will accept either an absolute or relative path; assuming that the name of our application is hello_world, either of these will work fine:
When you are ready, run the create command and you will get similar to the following output:
So here Phoenix has taken care of creating all of the directory structure and files for your app. You can take a look at what it is creating by navigating directly to the files in your code editor of choice.
When that's done, we see the prompt asking for dependencies to be installed. Proceed with yes:
Now that everything has downloaded, we can cd to the directory that Elixir has been populating the project files in, and create the database via mix ecto.create.
Note: if this is the first time you are running this command, Phoenix may also ask to install Rebar. Go ahead with the installation as Rebar is used to build Erlang packages.
Database Issues
If you see the following error:
Please ensure PostgreSQL service is running and accessible with the user credentials provided (by default the user postgres with a password of "postgres" is used).
Start Up the Phoenix Web Server!
We can now start the server for our Elixir app! Run the following:
By default, Phoenix is accepting requests on port 4000.
Visit http://localhost:4000, and you will see the Phoenix Framework welcome page.
If you can't see the page above, try accessing it via http://127.0.0.1:4000 (in case localhost is not defined on your OS).
Locally, we can now see requests being processed in our terminal session as our application is running in an iex session. To stop it, we hit ctrl-c twice, just as we would to stop iex normally.
Customising Your Application
When Phoenix generates a new application for us, it builds a top-level directory structure, as we'll see in the following section below.
We created a new application via the mix phoenix.new command, which generated a new application, including the directory structure as so:
For now we will be working on the web directory, which contains the following:
To change the logo at the top of the page, we need to edit the static assets, which are kept in priv/static. The logo is kept in the directory as so: priv/static/images/phoenix.png.
Feel free to add your own graphics here; we will link it in the css and begin modifying the template next. By default, Phoenix will compile any static assets (for example here in the images directory) to the production bundle.
For when we need a build phase for js or css, we place assets in web/static, and the source files are built into their respective app.js / app.css bundle within priv/static.
Modifying the CSS
The path for your css is web/static/css/phoenix.css. To change the logo, look to lines 29-36.
Make your change and save the file, and the changes will be updated automatically.
Reload your web browser, or load up http://localhost:4000.
Modifying Templates
To change the contents of your template, just look in the files in web/templates/layout and web/templates/page. You can start modifying the files to see changes live in your app.
The standard Phoenix templating engine uses EEx, which stands for Embedded Elixir. All template files have the extension .eex.
Templates are scoped to a view, which in turn are scoped to a controller.
Phoenix creates a web/templates directory where we can put all these. For the sake of organisation, it is best to namespace these, so if you want to create a new page, that means you need to create a new directory under web/templates and then create an index.html.eex file within it (e.g. web/templates/<My-New-Page>/index.html.eex).
Let's do that now. Create web/templates/about/index.html.eex and make it look like this:
Views
In Phoenix, the views part of the MVC design paradigm performs several important jobs.
For one, views render templates. Additionally, they act as a presentation layer for raw data from the controller, acting as a middle man in preparing it for use in a template.
For an example, take a common hypothetical data structure which represents a user with a first_name field and a last_name field. Now, for the template, we want to show the user's full name.
For the best approach, we write a function to concatenate first_name and last_name and provide us a helper in the view in order to write clean, concise and easily legible template code.
In order to render any templates for our AboutController, we need an AboutView.
Note: The names are significant here—the first part of the names of the view and controller must match up.
Create web/views/about_view.ex and make it look like this:
Routing
In order to see a new page, you will need to set up a route and a controller for your view and template.
As Phoenix works on the MVC paradigm, we need to fill in all the parts. It's not much work though.
In plain English: Routes map unique HTTP verb/path pairs to controller/action pairs for further execution.
Phoenix automatically generates a router file for us in a new application at web/router.ex. This is where we will be working for this following section.
The route for the default "Welcome to Phoenix!" page looks like this.
This means to catch all requests made by visiting http://localhost:4000/ in a browser (which issues an HTTP GET request) to the application's / root path and send all of those requests to the index function in the HelloPhoenix.PageController module defined in web/controllers/page_controller.ex.
The page we are going to build will simply say "About my app" when we point our browser to http://localhost:4000/about. You can fill in more information to suit your app in the template, so just go ahead and write in your HTML!
A New Route
For our about page, we need to define a route. So just open up web/router.ex in a text editor. By default, it will contain the following; for more information on routing, refer to the official Routing Guide.
For our about section, let's add the new route to the router for a GET request to /about. It will be processed by a HelloPhoenix.AboutController, which we will construct in the next part.
For the GET to /about, add this line to the scope "/" block of the router.ex:
The complete block will look like so:
The Controller
We have set up the route, the view, and the template. So let's now put all the parts together so that we can view it in the browser.
Controllers are defined as Elixir modules, and actions inside a controller are Elixir functions. The purpose of actions is to gather any data and perform any tasks needed for rendering.
For the /about route, we need a HelloWorld.AboutController module with an index/2 action.
For that, we need to create a web/controllers/about_controller.ex and put the following inside:
For more information on Controllers, refer to the official Controllers guide.
Controller Structure
All controller actions take two arguments. The first of these is conn, a struct which holds a load of data about the request.
The second is params, which are the request parameters. Here, we are not using params, and we avoid compiler warnings by adding the leading _.
The core of this action is render conn, "index.html". This tells Phoenix to find a template called index.html.eex and render it. Phoenix will look for the template in a directory named after our controller, so web/templates/hello.
Note: Using an atom as the template name will also work here: render conn, :index, for example when using an :index atom. But the template will be chosen based on the Accept headers, so for example "index.html" or "index.json".
Testing the New Route
Visiting the http://localhost:4000/about URL will now render the template, controller, view and route we have defined so far!
Actions
So now we have created a page and customised the app a little. But how do we actually do something with user input? Actions.
The requests for our about page will be handled by the HelloWorld.AboutController using the show action. As we already defined the controller in the last steps, we just need to add to the code a way to retain the variable which is passed via a URL like so: http://localhost:4000/about/weather.
We will now modify the code to map the new URL GET request param through the controller and eventually to the template, via using Elixir's pattern matching.
Add the following to the module in web/controllers/about_controller.ex:
A few points of interest here:
We pattern match against the params passed into the show function so that the appName variable will be bound to the value from the URL.
For our example URL (http://localhost:4000/about/weather), the appName variable would contain the value weather.
Within the show action, there is also passed a third argument for the render function: a key/value pair where the atom :appName is the key and the appName variable is passed as the value.
The full listing of web/controllers/about_controller.ex reads as so:
Embedded Elixir
To finally use the variable in our template first, we need to create a file for our show action.
Create the file web/templates/about/show.html.eex and add the following:
We use the special EEx <%= %> syntax for Embedded Elixir. The opening tag has a = sign, meaning that the Elixir code between will be executed, and in turn the output will replace the tag.
Our variable for app name appears as @appName. In this case, this is not a module attribute, but in fact it is a special bit of meta-programmed syntax which stands in for Map.get(assigns, :appName). The result is much nicer on the eyes and much easier to work with in a template.
Defining the Route
For us to be able to see the route http://localhost:4000/about/weather, for example, we need to define the route to link with the show action for the controller we just defined.
Now our work is complete! Try it out by visiting the URL http://localhost:4000/about/weather.
Conclusion
You now have the fundamental knowledge to create a Phoenix app, customise it graphically, and create routes, actions, controllers and views for your app.
We touched on the setup for PostgreSQL features of Ecto, but to go into more detail on the Model part of the MVC paradigm, please continue your reading in the Ecto guide.
As for user interactions and creating authentication, for example, please continue your learning at the Plug guide over at the official Phoenix documentation.