Phoenix Web Development
上QQ阅读APP看书,第一时间看更新

Passing data to our templates

One thing we will frequently want to do is pass some data along our controller down to the templates that are doing the display work, especially if there is any sort of conditional display logic or anything like that. If we run h Phoenix.Controller.render in our IEx terminal, we’ll see a definition for the function that matches the following:

def render(conn, template, assigns)

Right now, we’re passing along conn and index.html (remember that anything using the pipeline operator |> passes the result as the first argument into the next function), so let's also pass along some assigns. Specifically, we'll pass along a dummy data structure for our first poll. Open up poll_controller.ex and let's change the index function to be the following:

def index(conn, _params) do
poll = %{
title: "My First Poll",
options: [
{"Choice 1", 0},
{"Choice 2", 5},
{"Choice 3", 2}
]
}

conn
|> put_layout(:special)
|> render("index.html", poll: poll)
end

We're building a Poll dummy map with a simple title and three possible choices to vote on. We're also starting off this poll with zero votes for the first element, five for the second, and two for the third. We then modify the render statement in the controller to set the assigns with a key of poll and a value of poll. Let's take a look at the modified template now:

<h2>Poll: <%= @poll.title %></h2>

<%= for {option, votes} <- @poll.options do %>
<strong><%= option %></strong>: <%= votes %> votes
<br />
<% end %>

So now we have a reference to @poll (if you remember the assigns, we named one of the keys for the assigns as poll). Any assigns that you send from the controller will end up in the templates as @ (whatever the key for the assign was). This is just a simple shorthand syntax, but there is one major caveat to using this shortcut: if that named assign is not always set, it will throw an error when you try to load the page! The good news is that there is a simple way to get around this problem. @conn will be available in the top level of any template automatically (although it will need to get passed down to any partial templates that get called beyond the initial one), so you can also access the assigns via @conn.assigns[:key] (so, for example, @poll could also be accessed via @conn.assigns[:poll]).

Next, in our template, we have a list comprehension that, for each element in the list of options for the poll, we'll pattern match the tuple into separate option and votes values and render a small template of the name in bold and the current score for each. This is a very simple idea of a poll but it's helpful to understand in the long run. Now that we have a little bit of an interaction going between our controller and our templates, let's write a few tests to cover our code.