Building the poll controller

Okay, so now that we're rocking a very thorough understanding of the connection flow and how Phoenix is handling each step along the way, let's start building our own controllers, views, routes, and templates to display something when a user goes to /polls in the browser. We'll start off by creating a new file, lib/vocial_web/controllers/poll_controller.ex. Much like our page controller, we're going to give this file a really basic structure:

defmodule VocialWeb.PollController do
use VocialWeb, :controller

def index(conn, _params) do
render conn, "index.html"
end
end

Next, remember that every controller and function inside of a controller should have corresponding views and templates. Let's create lib/vocial_web/views/poll_view.ex and give it a base structure as well:

defmodule VocialWeb.PollView do
use VocialWeb, :view
end

And finally, let’s create our template directory (lib/vocial_web/templates/poll) and create an index.html.eex file inside of that directory:

<h2>Poll!</h2>

That should be enough for us to visit http://localhost:4000/polls, right?:

Oh no! We're still missing a critical element to our /polls response to the browser: the routes! Every time you create a new controller and action, these should be accompanied by route updates (assuming you want to make those public, anyway). Let's open up lib/vocial_web/router.ex:

defmodule VocialWeb.Router do
use VocialWeb, :router

pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end

pipeline :api do
plug :accepts, ["json"]
end

scope "/", VocialWeb do
pipe_through :browser # Use the default browser stack

get "/", PageController, :index
end

# Other scopes may use custom stacks.
# scope "/api", VocialWeb do
# pipe_through :api
# end
end

So here, we can see the definitions of our various pipelines (one for any requests coming through the browser and one for any requests coming from the API). As you can see, these are all just plug statements where the connection passes through each step of the pipeline, top to bottom. Then, we see the scope statement. You can think of this as the namespace for your variables. Anything accessible at the top level, for example, would just be in the root (/) namespace or path. You can also see an example of an /api scope, which is commented out (this is fine; we don't have a need for API pipelines and routes yet). What we’ll want to do here to make the Poll index function accessible to the browser is add the following line to our root scope:

get "/polls", PollController, :index

What we're saying in the preceding code is that any time the browser makes an HTTP GET request to our server, asking for the /polls path, we should route that request to our PollController. Specifically, we should be targeting the index function and passing the connection and any additional params to that function. Make that change, save the routes file, and then reload your browser (which should still be pointing to http://localhost:4000/polls)/ You should see the following instead:

This is some really great progress! Except...wait, why is the Phoenix logo and giant header getting added to the top? I thought we just added a single H2 tag and nothing else! Well, every template we render also includes a template!