I have some <select> elements in my application that are used in multiple places, like a list of countries or currencies.
Right now I’m loading the data in the controller and injecting into the template via render, but it’s a lot of repeated work as I need to load the data in every new/create/edit/update actions. Defining a plug for those actions would ease the work, but again I would need to do it for every controller.
Would be ok to break the rule of “never run queries from the view side” and create view helpers like country_select and currency_select loading data inside them? Something like
def country_select do
countries = Countries.list_countries
...
end
Yes they’re HTML specific. I just edited to make it more clear (hopefully).
The Countries.list_countries/0 in the example is my context. The view helper would call it to load all countries and return a list of tuples for populating the HTML select options.
I’m personally of the mind to never run queries in a view, it would make it a ‘hidden cost’.
You could make helpers to make passing it into a render better (you can even inject your own render helpers into your controllers, but then that starts to ‘hide the cost again’.
Honestly for something like Countries I’m guessing it does not change all that often, I’d probably just use Cachex or so (with a fallback to the database) to grab the data so it is not calling the database often, then call that from the view (via a helper of course). If the data changes in the database just tell Cachex to clear and re-acquire it (or just put in the new values directly) and can link to a phoenix pubsub for multi-system clearing on updates too.
@luizdamim We’ve wrestled with this question recently as well as we initially were doing some of this in view functions but as others mentioned these costs get hidden and its easy to end up with N+1 queries. Recently we began moving the data fetching functionality out of views and into controllers; we still format the option tuples in a view function, but we pass that an assign with the data.
@Kham do you mean you write a plug that fetches and assigns these values so that each controller function doesn’t have to embed that logic? I think is a good suggestion for cases where multiple views will need the same option lists.