Terence Chow
Terence Chow

Reputation: 11153

How to query an item in a nested relationship?

Phoenix Framework 1.0.2

I have a user_post_path() because I am making Users has_many Posts.

in my Posts controller I do:

def show(conn, %{"id" => id, "user_id" => user_id}) do
    post = Post |> Repo.get!(id)
    user = User |> Repo.get!(user_id) 
    render(conn, :index, post: post, user: user)
end

in my post/show.html I have:

<%= link "Edit", to: user_post_path(@conn, :edit, @user, @post) %>

First question, is it inefficient to write 2 queries? ie. Repo.get!(id) and Repo.get!(user_id)

Or is it more efficient to write something like this:

user_with_post = User |> Repo.get!(user_id) |> Repo.preload [:posts] |> #now do something to get posts.id = 5 for example

I assume it is more efficient to write one query, (please correct me if I'm wrong!), which leads me to my second question.

Once I preload posts, I can't simply Repo.get(post_id) because I get "not a queryable" error. What is the proper way to filter the posts of a user so that I only get the users details with the specific post id/ids I want?

Upvotes: 3

Views: 765

Answers (1)

Gazler
Gazler

Reputation: 84140

Both methods (calling Repo.get! twice and using Repo.preload) will make two queries. You can verify this by looking in your phoenix console when calling the show action.

However if there is a has many association but you only want one of the users posts, I would write:

def show(conn, %{"id" => id, "user_id" => user_id}) do
    user = User |> Repo.get!(user_id) 
    post = assoc(user, :posts) |> Repo.get!(post_id)
    render(conn, :index, post: post, user: user)
end

Using assoc/2 you can ensure that the post belongs to the user - which is what I believe you are trying to do.

Upvotes: 3

Related Questions