ashkan117

ashkan117

Preloaded associations and views patterns

I’m wondering how do people structure their JSON Api’s with Phoenix. Using the blogs example, let’s say I have a blogs view like the following

  def render("show.json", %{blog: blog}) do
    %{
      id: blog.id,
      title: blog.title,
      posts: render_many(blog.posts, PostView, "post.json")
    }

This runs into things like what if posts has its own associations like comments, etc.

In my controller maybe sometimes I don’t care about the associations and other times I do. This leads me to two main problems?

  1. Are there any standards people follow to handle when a view should try and render associations?
  2. Should there be some helper function in Phoenix.View that handles conditionally rendering associations?

For the first problem I’m just curious how people do something like the following

  def show(conn, %{"id" => id}) do
    blog = Blogs.get_blog_with_all(id)
    # assume no associations are preloaded
    render(conn, "show.json", blog: blog)
  end

  def some_action(conn, %{"id" => id}) do
    blog = Blogs.get_blog_with_all(id, preload: [:association_one, :association_two])
    # here I want to include the two associations in my view
    render(conn, "show_with_association_one_and_two.json", blog: blog)
  end

Having a specific view for each combination of association seems tedious.

For the second problem I mean something like having a helper function maybe_render_association that will add the field to the view if the association is loaded or it will not include the field at all. My thinking is we don’t want to return nil in the case that the association is not loaded since it’s not actually nil. That pattern would look like


def render() do
  def render("post.json", %{post: post}) do
    %{
      id: post.id,
      title: post.title,
      body: post.body,
      comments: render_many(post.comments, CommentView, "comment.json")
    }
    # it would be nice if we can have it inside the above map but 
    # since it's a conditional field not sure how
    |> maybe_render_association(post.updated_by, :updated_by, User, "basic.json")
  end
end

Most Liked

LostKobrakai

LostKobrakai

I don’t think phoenix should drive such helpers. I’d argue a none preloaded association reaching a view template expecting that association to be preloaded is an error. There’s no definitive answer to if that association is missing because of a bug, because of the intention to skip the key of the association in the json or because of the intention to mask the data not being loaded with an empty value ([] or nil). I’ve seen people argue in favor of all of these, so a generalize solution is likely not the answer.

You can however quite build such a helper for your project and your intentions.

Personally I’d push this concern to other places though. E.g. have PostUser – like a user as shown in relation to posts – vs a UserDetails – user as rendered by e.g. /users/:id. That requires more upfront modeling, but makes code a lot more explicit. You’re not passing around data, which could fit 10+ branches of results – and you hope you get the one you intend – but you pass around data that matches the one or few intented usecases. It also makes change easier, because the approach of a single very dynamic view template works great if all “branches” are kind of supersets of the base case. It gets hairy though once they have conflicting keys. Say eventually you want to mask part of the users as returned with posts, but not mask that for user details. It might feel like duplication at first, but going that route is more maintainable in the long run.

Where Next?

Popular in Discussions Top

matthias_toepp
I’d love to hear what people think about Wisp, the new Gleam web framework started by Gleam’s primary creator Louis Pilfold. Gleam, alon...
New
mikl
I wanted to capitalize a string, and tried using String.capitalize(). That generally works well, until you try to capitalize a word like...
New
jeramyRR
This is an interesting article to read. Elixir’s performance, like usual, is excellent. However, it seems like the high CPU usage is co...
New
Fl4m3Ph03n1x
Background A few days ago I was listening to The future of Elixir from Elixir Talks, with Dave Thomas (@pragdave ) and Brian Mitchell. I...
New
crabonature
I’m still quite new to Elixir. As I understand we got in Elixir “multi guards” as convention to simplify one large guard with or’s?: de...
New
tmbb
This is a post to discuss the new Phoenix LiveView functionality. From Chris’s talk, it appears that they generate all HTML on the serve...
342 18146 126
New
hazardfn
I suppose this question is effectively hackney vs. ibrowse but we are at a point in our project where we have to make a choice between th...
New
jesse
Hi everyone, I hesitated to post this here because I don’t want you to think I’m spamming, but I’ve been working on a Platform-as-a-Serv...
New
joeerl
I’m playing with Elixir - It’s fun. I think @rvirding does give Elixir courses these days. Re: files and database - when I given Erlang ...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41539 114
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement