插头连接或会话中的 KeyError

KeyError in Plug connection or session

所以我收到以下错误,因为我试图访问 :id 密钥。这里不足为奇。但是,我的实际问题是为什么将用户放在 :session 键内?这个插件是特定的吗?我不记得将用户设置为密钥 :session,如下面的视图所示。

错误:

** (KeyError) key :id not found in: 
%{
  session: %ExampleApp.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    email: "ka@example.com", 
    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"
}

导致错误的视图:

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

我必须执行以下操作才能访问用户信息:

...

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

如果有帮助,请看控制器:

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

我在这里做错了什么?预先感谢您的帮助。

However, my actual question is why is the user placed inside the :session key?

那是因为 render_one 尝试使用您传递的视图名称来猜测键名。在本例中,您传递了 SessionView,因此推断用于模型的密钥是 :session。如果您希望它位于 :user 中,您可以传递 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

您可以在 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

...