Adding Persistence to Slackir

So now we have a basic chat app but once our session is closed all of our messages are lost. If we were able to create, read, update and delete from a database we would be able to maintain a history of messages or have persistence across our application.

Creating our Database

First, we’ll create a migration and some code to handle persistence. Migrations are pieces of code that create or change database columns. In Phoenix, we can invoke mix phx.gen.context from the terminal to generate a context with functions, schema and migration:

$ mix phx.gen.context Conversations Message messages name:string message:string

Explanation on that command:

More on DB types you can find here.

Then run the migration:

$ mix ecto.migrate

Creating our messages in the Database

Next, we need to save the messages as they come in. If you are not familiar with programming this is create in the CRUD app methodology. In lib/slackir_web/channels/random_channel.ex, we can add a call to do it, so the handle_in method looks like this:

def handle_in("shout", payload, socket) do
  Slackir.Conversations.create_message(payload)
  broadcast socket, "shout", payload
  {:noreply, socket}
end

Refactor

The above code is alright, but if we want to scale our application we will start to have a problem as all the saves to the database will slow down the request cycle and keep us from handling the traffic efficiently. Elixir has some built in tools for dealing with exactly this situation. Specifically, Kernel.spawn, which takes a module, a method, and arguments to pass to the method. So we’ll update our handler, and add a method:

def handle_in("shout", payload, socket) do
  spawn(Slackir.Conversations, :create_message, [payload])
  broadcast! socket, "shout", payload
  {:noreply, socket}
end

What this does is spawn an elixir process to do the save, outside of the request cycle. Since we don’t need to see the results of the save to broadcast the message, there’s no reason to wait for it.

What's Next