插件连接或会话中的KeyError

时间:2016-08-25 01:36:02

标签: session connection elixir phoenix-framework

所以我收到了下面的错误,因为我试图访问: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

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

1 个答案:

答案 0 :(得分:2)

  

但是,我的实际问题是为什么用户放在:session键内?

那是因为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"
     

...

     

底层用户被传递给视图和模板:user,它从视图名称中转换。可以使用:as选项自定义分配中键的名称:

render_one user, UserView, "show.html", as: :data
     

...