Phoenix for Railsies

My last post covered WebSockets within the Ruby ecosystem with a particular focus on the support for WebSockets within Rails. As I was learning about the complex relationship between WebSockets and Ruby, I found a web framework that makes WebSockets easier while still letting us do things the “Rails way”. It’s called Phoenix. Although WebSockets is how I discovered Phoenix, it has a lot more to offer than just “easier WebSockets”.

Unfortunately (or fortunately, depending on how you look at things), Phoenix isn’t a Ruby framework. Instead, it is written and based in a language called Elixir that’s built on top of the Erlang virtual machine. In this article, we’ll take a look at why it makes sense to consider the Elixir+Phoenix combo as a Rubyist as well as the basics of the Phoenix framework.

Elixir

In order to understand what makes Elixir special, we have to understand a little bit about Erlang and the Erlang VM. Erlang was originally developed at Ericsson (which is, more or less, a telecom company) to build systems that stay up no matter what kind of madness is going on in the world. Although Erlang didn’t catch on like the plague, it’s been used for some pretty big projects by a lot of companies. Some examples: WhatsApp is powered by an Erlang-based architecture, Facebook initially used Erlang for its chat architecture and Basho (the company behind Riak) uses Erlang heavily and holds it in high regard. There are a number of reasons why Erlang is so good for building highly available distributed systems (e.g. the concept of supervisors is executed particularly well within Erlang). However, Erlang is a functional language with a number of idiosyncrasies that make it a bit unpleasant to use, for many.

Erlang runs on top of the Erlang Virtual Machine. If you’re familiar with Java, this is similar to the relationship between Java and the JVM. Elixir is another language that runs on top of the Erlang Virtual Machine. So, Elixir offers incredibly easy interop with Erlang (we can call Erlang functions at essentially no runtime cost) with a different syntax which, in my opinion, is more pleasing than the Erlang syntax.

If you’d like to quickly get up to speed with the basics of Elixir, we have a couple of articles you can skim through quickly. Even if you don’t have any experience with Elixir, but have some Ruby background, you’ll find that it isn’t too difficult to catch on to the Elixir way of things.

Phoenix

So, what is Phoenix? It’s a Rails-like framework built for Elixir. You might ask: what on Earth is the point of learning yet another framework for yet another language that nobody really seems to be using (yet)? There are a couple of reasons. First of all, the Erlang VM is pretty darn fast and Elixir inherits this speed. There are benchmarks that show this. But of course, we can sit around all day and poke holes in those so you’ll just have to build something with both technologies to believe it.

Secondly, Elixir is an interesting language because it manages to combine functional programming, OOP, and a Lisp-like conception of metaprogramming (Elixir’s macros are pretty insanely powerful). Finally, Rails definitely feels a bit behind-the-curve when it comes to things like WebSockets. Phoenix comes with these right of the box. Best of all, you get most of these benefits without having to leave the niceties of Rails behind. Granted, there aren’t as many packages for Phoenix as there are for Rails but the framework itself is fairly feature-complete. Let’s take a look at the basics of Phoenix.

Installation

We’ll zip through the installation steps mostly because they’re boring and there are other resources that probably explain them better (and we’ll link to these). First of all, you need to install Elixir which, fortunately, has a pretty coherent Install page. The Elixir equivalent of the RubyGems/Bundler couple is called “Mix”. We can use that to install Phoenix, as described on the Phoenix Install Page.

Build it

If I threw a bunch of theory at you, you’d probably forget nearly all of it by the time you finish reading this article. Instead, we’re going to build a small application with Phoenix to see how the sausage is made. If you follow along, the steps might seem a bit disconnected and random at first, but eventually, things should “click.”

So, what are we going to build? I’m constantly forgetting little things throughout the day and I’d like a way to be reminded while I’m banging out some code on my laptop. To solve this problem, we’re going to build a webapp that we can set reminders on and it’ll remind us via email. We could also do this with the HTML5 Notifications API, but we’ll demonstrate some important concepts within Phoenix with the email.

We can take a look at what we have so far after starting the server at http://127.0.0.1:4000. We can leave the server running because, just like Rails, the Phoenix server does live code reload. In order to get going with our “remynders” app, we have to modify the routing so that we can have a route that doesn’t end up at the Phoenix default page. Open up web/router.ex (more or less analogous to Rails’ config/routes.rb):

The only part of this we need to be concerned with at the moment is , where our rendered templates will simply be “dropped in” (again, incredibly similar to the Rails concept of application.html.erb). So, we’ve solved part of our problem, but aesthetics aren’t the best quality of Remynders…yet.

Static Files

We want to modify the CSS for both the layout and for a given page. Giving the top of web/static/css/app.scss a quick glance shows us that Phoenix comes with a copy of Bootstrap ready to go. Since this is a small app and we don’t care too much about supporting a ton of different browsers with a complex style, we’ll just get rid of Bootstrap. We’ll replace app.css with:

Helpers

Right now, our index page is more or less static. We want to link it up to a form that will let us a create a reminder. First of all, we need to fix up our routes so that we set up resource routing for a “Reminder” (exactly how we might in Rails):

resources "/reminders", ReminderController

That sets up the resource routes, but we need a ReminderController before stuff will start working. Again, we create a new controller in web/controllers/reminder_controller.ex:

Now, we’ll fix the link in the index page. First, use the URL helper in web/views/index_view.ex:

defmodule Remynders.IndexView do
use Remynders.Web, :view
alias Remynders.Router.Helpers
def new_reminder_path do
Helpers.reminder_path(Remynders.Endpoint, :new)
end
end

We can do that by opening up web/templates/index.html.eex and replacing:

<a href="#" class="button">Create a reminder</a>

with this:

<a href="<%= new_reminder_path %>" class="button">

So, here’s what we’ve done. First of all, we added an alias in the view:

alias Remynders.Router.Helpers

That just lets us refer to Remynders.Router.Helpers as just Helpers. Purely for convenience. Then, we used the actual URL helper:

Helpers.reminder_path(Remynders.Endpoint, :new)

Which defined that as a function within the view. This lets us call the function from the actual template to set up the link. All this seems really complicated compared to Rails’ link_to and it turns out that there’s another way. We mostly did this view function thing to demonstrate how we can call methods in the view from the template. We can actually replace our tag with an HTML helper:

Now, if you head over to the index page and click on the button you will get…an error page. We haven’t set up the view yet!

Until Next Time

So far, it might seem like we haven’t come very far. We’ve only served some very simple pages through Phoenix and barely worked out the URL helper. But, we’ve set a firm foundation on which we can build quickly with form helpers, models, background processing and the HTML5 notifications API. We’ll be covering a lot of that in the next article!

Further Reading

Some portions of Phoenix don’t have great documentation quite yet, but most of what we worked with can be found in the Phoenix guides. Phoenix also comes with a lot of reference documentation which can be pretty useful to figure out how to use a specific function. Most of the HTML-producing methods (e.g. link) available in the templates are a part of Phoenix.HTML which is documented separately.