Reputation: 4251
So I was getting the error below because I was trying to access the :id
key. No surprise here. However, my actual question is why is the user placed inside the :session
key? Is this Plug specific? I don't remember setting user to the key :session
as you can see in the view below.
Error:
** (KeyError) key :id not found in:
%{
session: %ExampleApp.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
email: "[email protected]",
first_name: "keith",
id: 356,
inserted_at: #Ecto.DateTime<2016-08-25 00:56:51>,
last_name: "a.",
updated_at: #Ecto.DateTime<2016-08-25 00:56:51>,
username: "keith"
},
view_module: ExampleApp.SessionView,
view_template: "show.json"
}
View that caused error:
defmodule ExampleApp.SessionView do
use ExampleApp.Web, :view
def render("show.json", %{jwt: jwt, user: user, exp: exp}) do
%{
jwt: jwt,
exp: exp,
user: render_one(user, __MODULE__, "show.json")
}
end
def render("show.json", user) do
%{
id: user.id, #<------------------------------------------ HERE
username: user.username,
last_name: user.last_name,
first_name: user.first_name
}
end
I had to do the following to access the user's information:
...
def render("show.json", user) do
%{
id: user.session.id, #<------------------------------------------ HERE
username: user.session.username,
last_name: user.session.last_name,
first_name: user.session.first_name
}
end
Here's the controller if it helps:
defmodule ExampleApp.RegistrationController do
use ExampleApp.Web, :controller
alias ExampleApp.{Repo, User, SessionView}
def create(conn, %{"user" => user_params}) do
changeset = User.new_changeset(%User{}, user_params)
case Repo.insert(changeset) do
{:ok, user} ->
{:ok, jwt, claims} = user |> Guardian.encode_and_sign(:token)
exp = Map.get(claims, "exp")
conn
|> put_status(:created)
|> render(SessionView, "show.json", %{jwt: jwt, user: user, exp: exp})
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render("error.json", changeset: changeset)
end
end
end
What am I doing wrong here? Thank you in advance for your help.
Upvotes: 1
Views: 172
Reputation: 222040
However, my actual question is why is the user placed inside the
:session
key?
That's because render_one
tries to guess the key name using the name of the view you passed. In this case, you passed SessionView
, so the key to use for the model is inferred to be :session
. If you instead want it to be in :user
, you can pass as: :user
:
def render("show.json", %{jwt: jwt, user: user, exp: exp}) do
%{
jwt: jwt,
exp: exp,
user: render_one(user, __MODULE__, "show.json", as: :user)
}
end
You can read more about this in the documentation for Phoenix.View.render_one/4.
...
render_one user, UserView, "show.html"
...
The underlying user is passed to the view and template as
:user
, which is inflected from the view name. The name of the key in assigns can be customized with the:as
option:render_one user, UserView, "show.html", as: :data
...
Upvotes: 2