Ecto嵌套关联查询范围问题:筛选当前用户所属记录失败
First, let's break down why your current code is throwing the Protocol.UndefinedError:
- When you preload
:leaguesfor the user,user.leaguesbecomes a list of League structs, not a queryable (like theLeagueschema module or an Ecto query). Repo.get/2expects its first argument to be a queryable (something Ecto can turn into a database query), not an in-memory list. That's why you're seeing the error about theEcto.Queryableprotocol not being implemented for a list.
Here are two clean solutions to fetch the league that belongs to the current user:
Solution 1: Direct Database Query (Recommended)
Instead of preloading all leagues first, query the League table directly with conditions for both the league ID and the current user's ID. This is more efficient because it only fetches the specific league you need from the database:
def show(conn, %{"id" => id}) do user_id = Map.get(Statcasters.Guardian.Plug.current_resource(conn), :id) # Fetch the league only if it belongs to the current user league = Repo.get_by(League, id: id, user_id: user_id) # Handle the case where the league doesn't exist or doesn't belong to the user if league do # Your existing logic here else # Return an error response, e.g., conn |> put_status(:not_found) |> json(%{error: "League not found"}) end end
Solution 2: Filter Preloaded List
If you already need the user's full list of leagues for other purposes, you can filter the preloaded list in memory instead of using Repo.get:
def show(conn, %{"id" => id}) do user_id = Map.get(Statcasters.Guardian.Plug.current_resource(conn), :id) user = Repo.get!(User, user_id) |> Repo.preload(:leagues) # Convert the string ID from params to integer (since league IDs are usually integers) league_id = String.to_integer(id) # Find the matching league in the preloaded list league = Enum.find(user.leagues, fn league -> league.id == league_id end) # Handle missing league case as above end
Note: Solution 1 is better for performance when you only need the single league, as it avoids loading all of the user's leagues into memory.
内容的提问来源于stack exchange,提问作者Bitwise

