In the last episode, we got our rough data model and persistence layer worked out. Now, we'd like to make our web app use that persistence layer when a user submits data.

The first step is to extract our Amnesia records from the test we built them in, directly into the application itself. Let's go ahead and do that by moving the database code into lib/dwitter/database.ex:

... hack hack hack ...

Now that that's done, we should be able to just feed the form data that was sent in by the user into a Dweet record, and show all the Dweets from newest to oldest on the homepage:

(The following needs to go in the lib/dwitter.ex file, before starting the Dwitter Dynamo:

Amnesia.Schema.create
Amnesia.start
Dwitter.Database.destroy
Dwitter.Database.create

So you are aware, for now this will blow away the database and recreate it each time we restart the server.

Now, let's modify the existing router and make it store a new Dweet each time the form is submitted. Open up web/routers/application_router.ex and add this to the post route:

    dweet = Amnesia.transaction do
      last_dweet = Dweet.last
      id = if last_dweet do
             last_dweet.id + 1
           else
             1
           end
      d = Dweet[id: id, content: conn.params[:content]]
      d.write
      d
    end
    conn = conn.assign(:dweet, dweet)

we also need to add use Twitter.Database to the top of the router.

Basically, we're finding the last dweet's id and incrementing it, or we're setting the first dweet's id to 1 here. There are definitely better ways to handle this I'm sure, but for now this gets the job done.

Finally, we've changed our assign to set @dweet to the dweet, rather than just sending the content like we did before. This requires us to change the post_complete.html.eex template. Change @content to @dweet.content.

Go ahead and test it out - the behaviour should be the same as before.

Let's also modify the homepage to show recent dweets. This part is a little awkward at present - I'm sure as these libraries mature, this sort of thing will get a little bit simpler.

For now, open up the application_router.ex and modify the / route to look like the following:

    recent_dweets = Amnesia.transaction do
      if Dweet.last do
        Dweet.to_sequence.reverse |> Enum.take(10)
      else
        nil
      end
    end
    conn = conn.assign(:recent_dweets, recent_dweets)

The bulk of the work here is in getting the (at most) last ten dweets. We're seeing the pipe (|>) operator for the first time as well, so I'll briefly describe it and then move on. In a later episode, we'll look at it in detail.

The pipe operator takes the output of the expression on the left of it, and passes it as the first argument to the expression on the right of it. This works very much like the pipe (|) in a unix shell.

This would be the equivalent of the following code:

all_dweets = Dweet.to_sequence.reverse
recent_dweets = Enum.take(all_dweets, 10)

As you can see, using the pipe operator is a lot more terse.

Anyway, the point is, we're grabbing the last 10 dweets and sending them to the template to render. Let's have a look at how you can render them in the template. Open up web/templates/index.html.eex and add this after the form close tag. I'm just going to type it all out before I start trying to explain it, and you're welcome to get a little frustrated...:

    <%= if @recent_dweets do %>
      <h4>Recent Dweets</h4>
      <ul>
        <%= Enum.join(Enum.map(@recent_dweets, fn(dweet) ->
"<li>#{dweet.content}</li>" end )) %>
      </ul>
    <% end %>

So until you get to the line that outputs the li's for each dweet, it's all kind of normal looking - then it goes all cross-eyed. This is because at present I'm not aware of a succinct way to render part of a template for each element in an Enumerable. No one on IRC piped up and suggested they'd done it before, so for now we just create a string representing each li, and join them, and output that into our template.

At any rate, it works, and we can verify it by creating a few dweets and visiting the homepage to see them appear in the list.

Summary

So that wraps up this episode. In it, we integrated what we knew about Amnesia with the existing Dynamo app we'd started building, so that we could persist some records into the mnesia database. We also saw the pipe operator for the first time - it'll come up often. See you soon!