{"__v":1,"_id":"5777c9635b2b430e00b982b4","category":{"version":"5777c9635b2b430e00b982a5","project":"54348ec95b10711400c6c445","_id":"5777c9635b2b430e00b982a7","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2014-10-09T04:18:04.869Z","from_sync":false,"order":1,"slug":"guides","title":"Guides"},"parentDoc":null,"project":"54348ec95b10711400c6c445","user":"5435e00ad7d8700800bbec51","version":{"__v":1,"_id":"5777c9635b2b430e00b982a5","project":"54348ec95b10711400c6c445","createdAt":"2016-07-02T14:02:11.084Z","releaseDate":"2016-07-02T14:02:11.084Z","categories":["5777c9635b2b430e00b982a6","5777c9635b2b430e00b982a7","5777c9635b2b430e00b982a8","5777c9635b2b430e00b982a9","5777c9635b2b430e00b982aa"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.2.0","version":"1.2.0"},"updates":["5489fb736e94d20b0017933d","54e8ae1100796519003a0a72","55073e33485d6519007223f0","55073ffec669f51900558311","55210d83252e880d0081d9b0","5553e3fda7de890d0003d48d","55e39506da10ec0d00032c36","55eb035989a92f0d0014174a","570c2b492627240e003e6330"],"next":{"pages":[],"description":""},"createdAt":"2014-12-03T22:05:04.535Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"never","params":[],"url":""},"isReference":false,"order":5,"body":"Phoenix views have two main jobs. First and foremost, they render templates (this includes layouts). The core function involved in rendering, `render/3`, is defined in Phoenix itself in the `Phoenix.View` module. Views also provide functions which take raw data and make it easier for templates to consume. If you are familiar with decorators or the facade pattern, this is similar.\n\n## Rendering Templates\n\nPhoenix assumes a strong naming convention from controllers to views to the templates they render. The `PageController` requires a `PageView` to render templates in the `web/templates/page` directory.\n\nIf we want to, we can change the directory Phoenix considers to be the template root. Phoenix provides a `view/0` function in the `HelloPhoenix.Web` module defined in `web/web.ex`. The first line of `view/0` allows us to change our root directory by changing the value assigned to the `:root` key.\n\nA newly generated Phoenix application has three view modules - `ErrorView`, `LayoutView`, and `PageView` -  which are all in the, `web/views` directory.\n\nLet's take a quick look at the `LayoutView`.\n\n```elixir\ndefmodule HelloPhoenix.LayoutView do\n  use HelloPhoenix.Web, :view\nend\n```\n\nThat's simple enough. There's only one line, `use HelloPhoenix.Web, :view`. This line calls the `view/0` function we just saw above. Besides allowing us to change our template root, `view/0` exercises the `__using__` macro in the `Phoenix.View` module. It also handles any module imports or aliases our application's view modules might need.\n\nAt the top of this guide, we mentioned that views are a place to put functions for use in our templates. Let's experiment with that a little bit.\n\nLet's open up our application layout template, `templates/layout/app.html.eex`, and change this line,\n\n```html\n<title>Hello Phoenix!</title>\n```\n\nto call a `title/0` function, like this.\n\n```elixir\n<title><%= title %></title>\n```\n\nNow let's add a `title/0` function to our `LayoutView`.\n\n```elixir\ndefmodule HelloPhoenix.LayoutView do\n  use HelloPhoenix.Web, :view\n\n  def title do\n    \"Awesome New Title!\"\n  end\nend\n```\n\nWhen we reload the Welcome to Phoenix page, we should see our new title.\n\nThe `<%=` and `%>` are from the Elixir [EEx](http://elixir-lang.org/docs/stable/eex/) project. They enclose executable Elixir code within a template. The `=` tells EEx to print the result. If the `=` is not there, EEx will still execute the code, but there will be no output. In our example, we are calling the `title/0` function from our `LayoutView` and printing the output into the title tag.\n\nNote that we didn't need to fully qualify `title/0` with `HelloPhoenix.LayoutView` because our `LayoutView` actually does the rendering.\n\nWhen we `use HelloPhoenix.Web, :view`, we get other conveniences as well. Since the `view/0` function imports `HelloPhoenix.Router.Helpers`, we don't have to fully qualify path helpers in templates. Let's see how that works by changing the template for our Welcome to Phoenix page.\n\nLet's open up the `templates/page/index.html.eex` and locate this stanza.\n\n```html\n<div class=\"jumbotron\">\n  <h2>Welcome to Phoenix!</h2>\n  <p class=\"lead\">A productive web framework that<br>does not compromise speed and maintainability.</p>\n</div>\n```\n\nThen let's add a line with a link back to the same page. (The objective is to see how path helpers respond in a template, not to add any functionality.)\n\n```html\n<div class=\"jumbotron\">\n  <h2>Welcome to Phoenix!</h2>\n  <p class=\"lead\">A productive web framework that<br>does not compromise speed and maintainability.</p>\n  <p><a href=\"<%= page_path :::at:::conn, :index %>\">Link back to this page</a></p>\n</div>\n```\n\nNow we can reload the page and view source to see what we have.\n\n```html\n<a href=\"/\">Link back to this page</a>\n```\n\nGreat, `page_path/2` evaluated to `/` as we would expect, and we didn't need to qualify it with `HelloPhoenix.View`.\n\n### More About Views\n\nYou might be wondering how views are able to work so closely with templates.\n\nThe `Phoenix.View` module gains access to template behavior via the `use Phoenix.Template` line in its `__using__/1` macro. `Phoenix.Template` provides many convenience methods for working with templates - finding them, extracting their names and paths, and much more.\n\nLet's experiment a little with one of the generated views Phoenix provides us, `web/views/page_view.ex`. We'll add a `message/0` function to it, like this.\n\n```elixir\ndefmodule HelloPhoenix.PageView do\n  use HelloPhoenix.Web, :view\n\n  def message do\n    \"Hello from the view!\"\n  end\nend\n```\n\nNow let's create a new template to play around with, `web/templates/page/test.html.eex`.\n\n```html\nThis is the message: <%= message %>\n```\n\nThis doesn't correspond to any action in our controller, but we'll exercise it in an `iex` session. At the root of our project, we can run `iex -S mix`, and then explicitly render our template.\n\n```console\niex(1)> Phoenix.View.render(HelloPhoenix.PageView, \"test.html\", %{})\n  {:safe, [[\"\" | \"This is the message: \"] | \"Hello from the view!\"]}\n```\nAs we can see, we're calling `render/3` with the individual view responsible for our test template, the name of our test template, and an empty map representing any data we might have wanted to pass in.\n\nThe return value is a tuple beginning with the atom `:safe` and the resultant string of the interpolated template.\n\n\"Safe\" here means that Phoenix has escaped the contents of our rendered template. Phoenix defines its own `Phoenix.HTML.Safe` protocol with implementations for atoms, bitstrings, lists, integers, floats, and tuples to handle this escaping for us as our templates are rendered into strings.\n\nWhat happens if we assign some key value pairs to the third argument of `render/3`? In order to find out, we need to change the template just a bit.\n\n```html\nI came from assigns: <%= @message %>\nThis is the message: <%= message %>\n```\n\nNote the `@` in the top line. Now if we change our function call, we see a different rendering after recompiling `PageView` module.\n\n```console\niex(2)> r HelloPhoenix.PageView\nweb/views/page_view.ex:1: warning: redefining module HelloPhoenix.PageView\n{:reloaded, HelloPhoenix.PageView, [HelloPhoenix.PageView]}\n\niex(3)> Phoenix.View.render(HelloPhoenix.PageView, \"test.html\", message: \"Assigns has an @.\")\n{:safe,\n  [[[[\"\" | \"I came from assigns: \"] | \"Assigns has an @.\"] |\n  \"\\nThis is the message: \"] | \"Hello from the view!\"]}\n ```\nLet's test out the HTML escaping, just for fun.\n\n```console\niex(4)> Phoenix.View.render(HelloPhoenix.PageView, \"test.html\", message: \"<script>badThings();</script>\")\n{:safe,\n  [[[[\"\" | \"I came from assigns: \"] |\n     \"&lt;script&gt;badThings();&lt;/script&gt;\"] |\n    \"\\nThis is the message: \"] | \"Hello from the view!\"]}\n```\n\nIf we need only the rendered string, without the whole tuple, we can use the `render_to_iodata/3`.\n\n ```console\n iex(5)> Phoenix.View.render_to_iodata(HelloPhoenix.PageView, \"test.html\", message: \"Assigns has an @.\")\n [[[[\"\" | \"I came from assigns: \"] | \"Assigns has an @.\"] |\n   \"\\nThis is the message: \"] | \"Hello from the view!\"]\n  ```\n\n### A Word About Layouts\n\nLayouts are just templates. They have a view, just like other templates. In a newly generated app, this is `web/views/layout_view.ex`. You may be wondering how the string resulting from a rendered view ends up inside a layout. That's a great question!\n\nIf we look at `web/templates/layout/app.html.eex`, just about in the middle of the `<body>`, we will see this.\n\n```html\n<%= render @view_module, @view_template, assigns %>\n```\n\nThis is where the view module and its template from the controller are rendered to a string and placed in the layout.\n\n### The ErrorView\n\nPhoenix has a view called the `ErrorView` which lives in `web/views/error_view.ex`. The purpose of the `ErrorView` is to handle two of the most common errors - `404 not found` and `500 internal error` - in a general way, from one centralized location. Let's see what it looks like.\n\n```elixir\ndefmodule HelloPhoenix.ErrorView do\n  use HelloPhoenix.Web, :view\n\n  def render(\"404.html\", _assigns) do\n    \"Page not found\"\n  end\n\n  def render(\"500.html\", _assigns) do\n    \"Server internal error\"\n  end\n\n  # In case no render clause matches or no\n  # template is found, let's render it as 500\n  def template_not_found(_template, assigns) do\n    render \"500.html\", assigns\n  end\nend\n```\n\nBefore we dive into this, let's see what the rendered `404 not found` message looks like in a browser. In the development environment, Phoenix will debug errors by default, showing us a very informative debugging page. What we want here, however, is to see what page the application would serve in production. In order to do that we need to set `debug_errors: false` in `config/dev.exs`.\n\n```elixir\nuse Mix.Config\n\nconfig :hello_phoenix, HelloPhoenix.Endpoint,\n  http: [port: 4000],\n  debug_errors: false,\n  code_reloader: true,\n  . . .\n```\n\nAfter modifying our config file, we need to restart our server in order for this change to take effect. After restarting the server, let's go to [http://localhost:4000/such/a/wrong/path](http://localhost:4000/such/a/wrong/path) for a running local application and see what we get.\n\nOk, that's not very exciting. We get the bare string \"Page not found\", displayed without any markup or styling.\n\nLet's see if we can use what we already know about views to make this a more interesting error page.\n\nThe first question is, where does that error string come from? The answer is right in the `ErrorView`.\n\n```elixir\ndef render(\"404.html\", _assigns) do\n  \"Page not found\"\nend\n```\n\nGreat, so we have a `render/2` function that takes a template and an `assigns` map, which we ignore. Where is this `render/2` function being called from?\n\nThe answer is the `render/5` function defined in the `Phoenix.Endpoint.RenderErrors` module. The whole purpose of this module is to catch errors and render them with a view, in our case, the `HelloPhoenix.ErrorView`.\n\nNow that we understand how we got here, let's make a better error page.\n\nPhoenix generates an `ErrorView` for us, but it doesn't give us a `web/templates/error` directory. Let's create one now. Inside our new directory, let's add a template, `not_found.html.eex` and give it some markup - a mixture of our application layout and a new `div` with our message to the user.\n\n\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"\">\n\n    <title>Welcome to Phoenix!</title>\n    <link rel=\"stylesheet\" href=\"/css/app.css\">\n  </head>\n\n  <body>\n    <div class=\"container\">\n      <div class=\"header\">\n        <ul class=\"nav nav-pills pull-right\">\n          <li><a href=\"http://www.phoenixframework.org/docs\">Get Started</a></li>\n        </ul>\n        <span class=\"logo\"></span>\n      </div>\n\n      <div class=\"jumbotron\">\n        <p>Sorry, the page you are looking for does not exist.</p>\n      </div>\n\n      <div class=\"footer\">\n        <p><a href=\"http://phoenixframework.org\">phoenixframework.org</a></p>\n      </div>\n\n    </div> <!-- /container -->\n    <script src=\"/js/app.js\"></script>\n  </body>\n</html>\n```\n\nNow we can use the `render/2` function we saw above when we were experimenting with rendering in the `iex` session.\n\nOur `render/2` function should look like this when we've modified it.\n\n```elixir\ndef render(\"404.html\", _assigns) do\n  render(\"not_found.html\", %{})\nend\n```\n\nWhen we go back to [http://localhost:4000/such/a/wrong/path](http://localhost:4000/such/a/wrong/path), we should see a much nicer error page.\n\nIt is worth noting that we did not render our `not_found.html.eex` template through our application layout, even though we want our error page to have the look and feel of the rest of our site. The main reason is that it's easy to run into edge case issues while handling errors globally.\n\nIf we want to minimize duplication between our application layout and our `not_found.html.eex` template, we can implement shared templates for our header and footer. Please see the [Template Guide](http://www.phoenixframework.org/docs/templates#section-shared-templates-across-views) for more information.\n\nOf course, we can do these same steps with the `def render(\"500.html\", _assigns) do` clause in our `ErrorView` as well.\n\nWe can also use the `assigns` map passed into any `render/2` clause in the `ErrorView`, instead of discarding it, in order to display more information in our templates.\n\n## Rendering JSON\n\nThe view's other job besides rendering templates is to render JSON. Phoenix uses [Poison](https://github.com/devinus/poison) to encode Maps to JSON, so all we need to do in our views is format the data we'd like to respond with as a Map, and Phoenix will do the rest.\n\nIt is possible to respond with JSON back directly from the controller and skip the View. However, if we think about a controller as having the responsibilities of receiving a request and fetching data to be sent back, data manipulation and formatting don't fall under those responsibilities. A view gives us a module responsible for formatting and manipulating the data.\n\nLet's take our `PageController`, and see what it might look like when we respond with some static page maps as JSON, instead of HTML.\n\n```elixir\ndefmodule HelloPhoenix.PageController do\n  use HelloPhoenix.Web, :controller\n\n  def show(conn, _params) do\n    page = %{title: \"foo\"}\n\n    render conn, \"show.json\", page: page\n  end\n\n  def index(conn, _params) do\n    pages = [%{title: \"foo\"}, %{title: \"bar\"}]\n\n    render conn, \"index.json\", pages: pages\n  end\nend\n```\n\nHere, we have our `show/2` and `index/2` actions returning static page data. Instead of passing in `\"show.html\"` to `render/3` as the template name, we pass `\"show.json\"`.  This way, we can have views that are responsible for rendering HTML as well as JSON by pattern matching on different file types.\n\n```elixir\ndefmodule HelloPhoenix.PageView do\n  use HelloPhoenix.Web, :view\n\n  def render(\"index.json\", %{pages: pages}) do\n    %{data: render_many(pages, HelloPhoenix.PageView, \"page.json\")}\n  end\n\n  def render(\"show.json\", %{page: page}) do\n    %{data: render_one(page, HelloPhoenix.PageView, \"page.json\")}\n  end\n\n  def render(\"page.json\", %{page: page}) do\n    %{title: page.title}\n  end\nend\n```\n\nIn the view we see our `render/2` function pattern matching on `\"index.json\"`, `\"show.json\"`, and `\"page.json\"`. In our controller `show/2` function, `render conn, \"show.json\", page: page` will pattern match on the matching name and extension in the view `render/3` functions.\n\nIn other words, `render conn, \"index.json\", pages: pages` will call `render(\"index.json\", %{pages: pages})`\n\nThe `render_many/3` function takes the data we want to respond with (`pages`), a `View`, and a string to pattern match on the `render/3` function defined on `View`. It will map over each item in `pages`, and pass the item to the `render/3` function in `View` matching the file string.\n\n`render_one/3` follows, the same signature, ultimately using the `render/3` matching `page.json` to specifiy what each `page` looks like.\n\nThe `render/3` matching `\"index.json\"` will respond with JSON as you would expect:\n\n```javascript\n  {\n    \"data\": [\n      {\n       \"title\": \"foo\"\n      },\n      {\n       \"title\": \"bar\"\n      },\n   ]\n  }\n```\n\nAnd the `render/3` matching `\"show.json\"`:\n\n```javascript\n  {\n    \"data\": {\n      \"title\": \"foo\"\n    }\n  }\n```\n\nIt's useful to build our views like this so they can be composable.  Imagine a situation where our `Page` has a `has_many` relationship with `Author`, and depending on the request, we may want to send back `author` data with the `page`. We can easily accomplish this with a new `render/3`:\n\n\n```elixir\ndefmodule HelloPhoenix.PageView do\n  use HelloPhoenix.Web, :view\n\n  def render(\"page_with_authors.json\", %{page: page}) do\n    %{title: page.title,\n      authors: render_many(page.authors, HelloPhoenix.AuthorView, \"author.json\")}\n  end\n\n  def render(\"page.json\", %{page: page}) do\n    %{title: page.title}\n  end\nend\n```","excerpt":"","slug":"views","type":"basic","title":"Views"}
Phoenix views have two main jobs. First and foremost, they render templates (this includes layouts). The core function involved in rendering, `render/3`, is defined in Phoenix itself in the `Phoenix.View` module. Views also provide functions which take raw data and make it easier for templates to consume. If you are familiar with decorators or the facade pattern, this is similar. ## Rendering Templates Phoenix assumes a strong naming convention from controllers to views to the templates they render. The `PageController` requires a `PageView` to render templates in the `web/templates/page` directory. If we want to, we can change the directory Phoenix considers to be the template root. Phoenix provides a `view/0` function in the `HelloPhoenix.Web` module defined in `web/web.ex`. The first line of `view/0` allows us to change our root directory by changing the value assigned to the `:root` key. A newly generated Phoenix application has three view modules - `ErrorView`, `LayoutView`, and `PageView` - which are all in the, `web/views` directory. Let's take a quick look at the `LayoutView`. ```elixir defmodule HelloPhoenix.LayoutView do use HelloPhoenix.Web, :view end ``` That's simple enough. There's only one line, `use HelloPhoenix.Web, :view`. This line calls the `view/0` function we just saw above. Besides allowing us to change our template root, `view/0` exercises the `__using__` macro in the `Phoenix.View` module. It also handles any module imports or aliases our application's view modules might need. At the top of this guide, we mentioned that views are a place to put functions for use in our templates. Let's experiment with that a little bit. Let's open up our application layout template, `templates/layout/app.html.eex`, and change this line, ```html <title>Hello Phoenix!</title> ``` to call a `title/0` function, like this. ```elixir <title><%= title %></title> ``` Now let's add a `title/0` function to our `LayoutView`. ```elixir defmodule HelloPhoenix.LayoutView do use HelloPhoenix.Web, :view def title do "Awesome New Title!" end end ``` When we reload the Welcome to Phoenix page, we should see our new title. The `<%=` and `%>` are from the Elixir [EEx](http://elixir-lang.org/docs/stable/eex/) project. They enclose executable Elixir code within a template. The `=` tells EEx to print the result. If the `=` is not there, EEx will still execute the code, but there will be no output. In our example, we are calling the `title/0` function from our `LayoutView` and printing the output into the title tag. Note that we didn't need to fully qualify `title/0` with `HelloPhoenix.LayoutView` because our `LayoutView` actually does the rendering. When we `use HelloPhoenix.Web, :view`, we get other conveniences as well. Since the `view/0` function imports `HelloPhoenix.Router.Helpers`, we don't have to fully qualify path helpers in templates. Let's see how that works by changing the template for our Welcome to Phoenix page. Let's open up the `templates/page/index.html.eex` and locate this stanza. ```html <div class="jumbotron"> <h2>Welcome to Phoenix!</h2> <p class="lead">A productive web framework that<br>does not compromise speed and maintainability.</p> </div> ``` Then let's add a line with a link back to the same page. (The objective is to see how path helpers respond in a template, not to add any functionality.) ```html <div class="jumbotron"> <h2>Welcome to Phoenix!</h2> <p class="lead">A productive web framework that<br>does not compromise speed and maintainability.</p> <p><a href="<%= page_path @conn, :index %>">Link back to this page</a></p> </div> ``` Now we can reload the page and view source to see what we have. ```html <a href="/">Link back to this page</a> ``` Great, `page_path/2` evaluated to `/` as we would expect, and we didn't need to qualify it with `HelloPhoenix.View`. ### More About Views You might be wondering how views are able to work so closely with templates. The `Phoenix.View` module gains access to template behavior via the `use Phoenix.Template` line in its `__using__/1` macro. `Phoenix.Template` provides many convenience methods for working with templates - finding them, extracting their names and paths, and much more. Let's experiment a little with one of the generated views Phoenix provides us, `web/views/page_view.ex`. We'll add a `message/0` function to it, like this. ```elixir defmodule HelloPhoenix.PageView do use HelloPhoenix.Web, :view def message do "Hello from the view!" end end ``` Now let's create a new template to play around with, `web/templates/page/test.html.eex`. ```html This is the message: <%= message %> ``` This doesn't correspond to any action in our controller, but we'll exercise it in an `iex` session. At the root of our project, we can run `iex -S mix`, and then explicitly render our template. ```console iex(1)> Phoenix.View.render(HelloPhoenix.PageView, "test.html", %{}) {:safe, [["" | "This is the message: "] | "Hello from the view!"]} ``` As we can see, we're calling `render/3` with the individual view responsible for our test template, the name of our test template, and an empty map representing any data we might have wanted to pass in. The return value is a tuple beginning with the atom `:safe` and the resultant string of the interpolated template. "Safe" here means that Phoenix has escaped the contents of our rendered template. Phoenix defines its own `Phoenix.HTML.Safe` protocol with implementations for atoms, bitstrings, lists, integers, floats, and tuples to handle this escaping for us as our templates are rendered into strings. What happens if we assign some key value pairs to the third argument of `render/3`? In order to find out, we need to change the template just a bit. ```html I came from assigns: <%= @message %> This is the message: <%= message %> ``` Note the `@` in the top line. Now if we change our function call, we see a different rendering after recompiling `PageView` module. ```console iex(2)> r HelloPhoenix.PageView web/views/page_view.ex:1: warning: redefining module HelloPhoenix.PageView {:reloaded, HelloPhoenix.PageView, [HelloPhoenix.PageView]} iex(3)> Phoenix.View.render(HelloPhoenix.PageView, "test.html", message: "Assigns has an @.") {:safe, [[[["" | "I came from assigns: "] | "Assigns has an @."] | "\nThis is the message: "] | "Hello from the view!"]} ``` Let's test out the HTML escaping, just for fun. ```console iex(4)> Phoenix.View.render(HelloPhoenix.PageView, "test.html", message: "<script>badThings();</script>") {:safe, [[[["" | "I came from assigns: "] | "&lt;script&gt;badThings();&lt;/script&gt;"] | "\nThis is the message: "] | "Hello from the view!"]} ``` If we need only the rendered string, without the whole tuple, we can use the `render_to_iodata/3`. ```console iex(5)> Phoenix.View.render_to_iodata(HelloPhoenix.PageView, "test.html", message: "Assigns has an @.") [[[["" | "I came from assigns: "] | "Assigns has an @."] | "\nThis is the message: "] | "Hello from the view!"] ``` ### A Word About Layouts Layouts are just templates. They have a view, just like other templates. In a newly generated app, this is `web/views/layout_view.ex`. You may be wondering how the string resulting from a rendered view ends up inside a layout. That's a great question! If we look at `web/templates/layout/app.html.eex`, just about in the middle of the `<body>`, we will see this. ```html <%= render @view_module, @view_template, assigns %> ``` This is where the view module and its template from the controller are rendered to a string and placed in the layout. ### The ErrorView Phoenix has a view called the `ErrorView` which lives in `web/views/error_view.ex`. The purpose of the `ErrorView` is to handle two of the most common errors - `404 not found` and `500 internal error` - in a general way, from one centralized location. Let's see what it looks like. ```elixir defmodule HelloPhoenix.ErrorView do use HelloPhoenix.Web, :view def render("404.html", _assigns) do "Page not found" end def render("500.html", _assigns) do "Server internal error" end # In case no render clause matches or no # template is found, let's render it as 500 def template_not_found(_template, assigns) do render "500.html", assigns end end ``` Before we dive into this, let's see what the rendered `404 not found` message looks like in a browser. In the development environment, Phoenix will debug errors by default, showing us a very informative debugging page. What we want here, however, is to see what page the application would serve in production. In order to do that we need to set `debug_errors: false` in `config/dev.exs`. ```elixir use Mix.Config config :hello_phoenix, HelloPhoenix.Endpoint, http: [port: 4000], debug_errors: false, code_reloader: true, . . . ``` After modifying our config file, we need to restart our server in order for this change to take effect. After restarting the server, let's go to [http://localhost:4000/such/a/wrong/path](http://localhost:4000/such/a/wrong/path) for a running local application and see what we get. Ok, that's not very exciting. We get the bare string "Page not found", displayed without any markup or styling. Let's see if we can use what we already know about views to make this a more interesting error page. The first question is, where does that error string come from? The answer is right in the `ErrorView`. ```elixir def render("404.html", _assigns) do "Page not found" end ``` Great, so we have a `render/2` function that takes a template and an `assigns` map, which we ignore. Where is this `render/2` function being called from? The answer is the `render/5` function defined in the `Phoenix.Endpoint.RenderErrors` module. The whole purpose of this module is to catch errors and render them with a view, in our case, the `HelloPhoenix.ErrorView`. Now that we understand how we got here, let's make a better error page. Phoenix generates an `ErrorView` for us, but it doesn't give us a `web/templates/error` directory. Let's create one now. Inside our new directory, let's add a template, `not_found.html.eex` and give it some markup - a mixture of our application layout and a new `div` with our message to the user. ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <title>Welcome to Phoenix!</title> <link rel="stylesheet" href="/css/app.css"> </head> <body> <div class="container"> <div class="header"> <ul class="nav nav-pills pull-right"> <li><a href="http://www.phoenixframework.org/docs">Get Started</a></li> </ul> <span class="logo"></span> </div> <div class="jumbotron"> <p>Sorry, the page you are looking for does not exist.</p> </div> <div class="footer"> <p><a href="http://phoenixframework.org">phoenixframework.org</a></p> </div> </div> <!-- /container --> <script src="/js/app.js"></script> </body> </html> ``` Now we can use the `render/2` function we saw above when we were experimenting with rendering in the `iex` session. Our `render/2` function should look like this when we've modified it. ```elixir def render("404.html", _assigns) do render("not_found.html", %{}) end ``` When we go back to [http://localhost:4000/such/a/wrong/path](http://localhost:4000/such/a/wrong/path), we should see a much nicer error page. It is worth noting that we did not render our `not_found.html.eex` template through our application layout, even though we want our error page to have the look and feel of the rest of our site. The main reason is that it's easy to run into edge case issues while handling errors globally. If we want to minimize duplication between our application layout and our `not_found.html.eex` template, we can implement shared templates for our header and footer. Please see the [Template Guide](http://www.phoenixframework.org/docs/templates#section-shared-templates-across-views) for more information. Of course, we can do these same steps with the `def render("500.html", _assigns) do` clause in our `ErrorView` as well. We can also use the `assigns` map passed into any `render/2` clause in the `ErrorView`, instead of discarding it, in order to display more information in our templates. ## Rendering JSON The view's other job besides rendering templates is to render JSON. Phoenix uses [Poison](https://github.com/devinus/poison) to encode Maps to JSON, so all we need to do in our views is format the data we'd like to respond with as a Map, and Phoenix will do the rest. It is possible to respond with JSON back directly from the controller and skip the View. However, if we think about a controller as having the responsibilities of receiving a request and fetching data to be sent back, data manipulation and formatting don't fall under those responsibilities. A view gives us a module responsible for formatting and manipulating the data. Let's take our `PageController`, and see what it might look like when we respond with some static page maps as JSON, instead of HTML. ```elixir defmodule HelloPhoenix.PageController do use HelloPhoenix.Web, :controller def show(conn, _params) do page = %{title: "foo"} render conn, "show.json", page: page end def index(conn, _params) do pages = [%{title: "foo"}, %{title: "bar"}] render conn, "index.json", pages: pages end end ``` Here, we have our `show/2` and `index/2` actions returning static page data. Instead of passing in `"show.html"` to `render/3` as the template name, we pass `"show.json"`. This way, we can have views that are responsible for rendering HTML as well as JSON by pattern matching on different file types. ```elixir defmodule HelloPhoenix.PageView do use HelloPhoenix.Web, :view def render("index.json", %{pages: pages}) do %{data: render_many(pages, HelloPhoenix.PageView, "page.json")} end def render("show.json", %{page: page}) do %{data: render_one(page, HelloPhoenix.PageView, "page.json")} end def render("page.json", %{page: page}) do %{title: page.title} end end ``` In the view we see our `render/2` function pattern matching on `"index.json"`, `"show.json"`, and `"page.json"`. In our controller `show/2` function, `render conn, "show.json", page: page` will pattern match on the matching name and extension in the view `render/3` functions. In other words, `render conn, "index.json", pages: pages` will call `render("index.json", %{pages: pages})` The `render_many/3` function takes the data we want to respond with (`pages`), a `View`, and a string to pattern match on the `render/3` function defined on `View`. It will map over each item in `pages`, and pass the item to the `render/3` function in `View` matching the file string. `render_one/3` follows, the same signature, ultimately using the `render/3` matching `page.json` to specifiy what each `page` looks like. The `render/3` matching `"index.json"` will respond with JSON as you would expect: ```javascript { "data": [ { "title": "foo" }, { "title": "bar" }, ] } ``` And the `render/3` matching `"show.json"`: ```javascript { "data": { "title": "foo" } } ``` It's useful to build our views like this so they can be composable. Imagine a situation where our `Page` has a `has_many` relationship with `Author`, and depending on the request, we may want to send back `author` data with the `page`. We can easily accomplish this with a new `render/3`: ```elixir defmodule HelloPhoenix.PageView do use HelloPhoenix.Web, :view def render("page_with_authors.json", %{page: page}) do %{title: page.title, authors: render_many(page.authors, HelloPhoenix.AuthorView, "author.json")} end def render("page.json", %{page: page}) do %{title: page.title} end end ```