Can the View access the context?

Do you think that the View can access the context, or that only the Controller should fetch the data from the context and put it in conn.assigns (and template passes data to the View) ?

Imagine the following example: we want to display a form to create a new post in our blog. In this form, there should be a select element allowing to select the category the post belongs to.

The View provides a helper category_select_options for the template, returning the data for the select element.

1. The View accesses the context:

defmodule MyAppWeb.PostView do
  use MyAppWeb, :view

  def category_select_options() do
    categories = Blog.list_categories() # the View fetches data from the Context

    for category <- categories,
        do: {
          category.name
          category.id
        }
  end
end

The template calls the function without any argument:

<%= select f, :category_id, category_select_options() %>

2. The Controller fetches and assigns the data in the conn; the template passes the data to the View

defmodule MyAppWeb.PostController do
  use MyAppWeb, :controller

  alias MyApp.Blog

  plug :assign_categories when action in [:new, :create, :edit, :update]

  defp assign_categories(conn, _) do
    assign(conn, :categories, Blog.list_categories())
  end

  # actions' code
end

defmodule MyAppWeb.PostView do
  use MyAppWeb, :view

  def category_select_options(categories) do
    for category <- categories,
        do: {
          category.name
          category.id
        }
  end
end

The template passes the @categories from conn.assigns to the View, which prepares the data for the select element:

<%= select f, :category_id, category_select_options(@categories) %>

Which do you think is better and most importantly why?

The latter is the way to go:

Controllers take the request and handle it, while Views should do a pure transformation of the inputs the controller provided to the needed output format (html, json, …).

The template is part of the view module, not something separate.

What is the disadvantage that the View accesses the Context? The Context eventually offers a clear API to access the data. I currently can’t see the drawback of using that API in both the Controller and the functions used as helpers in the View.

Views become less composable, and refactoring becomes more tricky, because you need to change views and controllers. Having a stable API is great, but the problems surface if there needs to be change.

1 Like

What would be an example of view composability?

Say an internal form in your app should additionally be made available publicly, but with different options for the select. You’d need to edit the view or copy the template if you do it by your first way. For the second you simply create a new controller, fetch the different options and render the exact same form template as the existing controller.

2 Likes