Elixir/Phoenix — Build a simple chat room

With Coherence, Channels and Presence

Hello, how are you?

In this blog post I want to discuss how to write a very simple chat room with a list of online users. The user will need to register an account before being able to enter the chat room. We will use both elixir and JavaScript, as well as a brand new authentication package I’ve been dabbling a bit with.

Modules and dependencies

Coherence

“Coherence is a full featured, configurable authentication

system for Phoenix”

For those of you who are coming from Ruby on Rails, this package will look familiar to the lovely Devise gem. Be aware that Coherence is in the early release stages, and the project is under active development. Things may change! Read more at https://github.com/smpallen99/coherence

Phoenix Channels

For client-server communication over web sockets.

Phoenix Presence

Provides tracking for processes and channels.

Setting up the project

We’ll start off by creating our new project, I will call mine Chatourious:

~/$ mix phoenix.new chatourius

* creating chatourius/config/config.exs

* creating chatourius/config/dev.exs

Fetch and install dependencies? [Yn] y

...

~/$ cd chatourius/

~/chatourius$ mix ecto.create

...

The database for Chatourius.Repo has been created

Next, we’ll add Coherence, run mix deps.get and restart our server:

#mix.exs

...... def application do

[mod: {Chatourius, []},

applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,

:phoenix_ecto, :postgrex, :coherence]]

end ...... defp deps do

[{:phoenix, “~> 1.2.1”},

{:phoenix_pubsub, “~> 1.0”},

{:phoenix_ecto, “~> 3.0”},

{:postgrex, “>= 0.0.0”},

{:phoenix_html, “~> 2.6”},

{:phoenix_live_reload, “~> 1.0”, only: :dev},

{:gettext, “~> 0.11”},

{:cowboy, “~> 1.0”},

{:coherence, “~> 0.3”}]

end ......

Coherence comes with different modules just like Devise- Authenticatable, Invitable, Registerable, Confirmable and so on. We’ll use the built in Coherence installer to generate some boilerplate files. We’ll run the installer without the confirmable option:

~/chatourius$ mix coherence.install — full-invitable

Your config/config.exs file was updated.

Compiling 12 files (.ex)

The installer also gave us some instructions on updating some files manually.

This is my updated routes:

# web/router.ex defmodule Chatourius.Router do

use Chatourius.Web, :router

use Coherence.Router pipeline :browser do

plug :accepts, ["html"]

plug :fetch_session

plug :fetch_flash

plug :protect_from_forgery

plug :put_secure_browser_headers

plug Coherence.Authentication.Session # Add this

end



# Add this block

pipeline :protected do

plug :accepts, ["html"]

plug :fetch_session

plug :fetch_flash

plug :protect_from_forgery

plug :put_secure_browser_headers

plug Coherence.Authentication.Session, protected: true # Add this

end pipeline :api do

plug :accepts, ["json"]

end scope "/" do

pipe_through :browser

coherence_routes

end # Add this block

scope "/" do

pipe_through :protected

coherence_routes :protected

end scope "/", Chatourius do

pipe_through :browser # Use the default browser stack



end # Add this block

scope "/", Chatourius do

pipe_through :protected

# Add protected routes below

get "/", PageController, :index

end

end

I’ve also moved our page_controller route to the protected scope, so that the users need to log in to see it. Adding and editing model fields are beyond the scope of this blog, however, I just want to make a tiny change to the registration field name label:

# web/templates/coherence/registration/form.html.eex

...... <div class="form-group">

<%= required_label f, :username, class: "control-label" %>

<%= text_input f, :name, class: "form-control", required: ""%>

<%= error_tag f, :name %>

</div> ......

Also, we’ll add the jQuery CDN url at the bottom our app.html.eex file:

We’ll run mix ecto.migrate, and restart our application. Now, after we’ve admired the amazing boilerplate templates for a while, we create a new account and sign into our application.

Building a simple interface

For simplicity, we’ll just stash our chat inside our Page Controller’s index template. First, delete everything inside the template located in web/templates/page/index.html.eex.

We’ll also delete the customized container css in web/static/css/phoenix.css:

This block of css code needs to go...

.container {

max-width: 730px;

}

} @media (min-width: 768px) {.container {max-width: 730px;

After removing the content of index template and removing the container block

Perfect. A nice, white and spotless canvas for us to fill with amazing design! Jokes aside, let’s start writing some html. We will use minimal css, and stick with the building blocks Twitter Bootstrap already provides us with:

# web/templates/page/index.html.eex

<div class="chat container">

<div class="col-md-9">

<div class="panel panel-default chat-room">

<div class="panel-heading">

Hello <%= Coherence.current_user(

<%= link "Sign out", to: session_path(

method: :delete %>

</div>

<div id="chat-messages" class="panel-body panel-messages">

</div> Hello @conn ).name %>@conn , :delete),method: :delete %> <input type="text" id="message-input" class="form-control"

placeholder="Type a message…"> </div>

</div>

<div class="col-md-3">

<div class="panel panel-default chat-room">

<div class="panel-heading">

Online Users

</div>

<div class="panel-body panel-users" id="online-users">

</div>

</div>

</div>

</div>

Notice that we can fetch our current user with the help of a built in Coherence helper, Coherence.current_user(@conn).name .

Our css goes into our app.css file:

.chat {

margin-top: 0em;

} .chat-room {

margin-top: 1em;

} .panel-messages, .panel-users {

height: 400px;

} #chat-messages {

min-height: 400px;

overflow-y: scroll;

}

And this is what we’ll end up with: