Shared Templates and Context Functions

I was wondering what would be consider best practice when using shared view templates which generously uses the context helper functions.

Currently the way that I am going about this is to alias the context in the view module and using the functions directly in the view. For example:

View:

defmodule MyAppWeb.SharedView do

  alias MyApp.Accounts
  alias MyApp.Topics
  ...
end

Shared template:

<div>
  <%= Accounts.get_user_name(user_id) %>
  ...
  <%= Topics.get_topic(topic_id) %>
  ...

</div>

Context:

  def get_user_name(%User{} = user) do
    Repo.get(User, id).name
  end
  def get_topic(%Topic{} = topic) do
    Repo.get(Topic, id)
  end

I feel like wrapping the Ecto repo related functions in view functions seems kind of round about way of doing things when you have many Ecto repo calls and preloading the data in controller would also be a tedious thing to do when you want the shared template to exists on many different pages which would have different controllers.

You can and should write a plug which fetches these from the database and assigns them on the conn.

This is the equivalent of doing it in the controller—except in a way that’s shared between all the controllers that need it, instead of having to be repeated for each one.

You really should avoid running database queries from inside your views. It’s very easy to end up in a situation with N+1 queries, and more generally it obscures the which actual database queries take place.

Thanks for the help @zzq.

I wasn’t sure if using a Plug was right because that solution might have been a little too much, but in the case of heavy database call functions, it would make sense.

1 Like