ex_admin
ex_admin copied to clipboard
ExAdmin automatically picking up my User module
I'm using ExAdmin with Guardian and Ueberauth. Guardian and Ueberauth uses very simple user logic for now:
# lib/kcc/user.ex
defmodule KCC.User do
@derive [Poison.Encoder]
defstruct email: nil, name: nil
end
defmodule KCC.UserSerializer do
@behaviour Guardian.Serializer
alias KCC.User
def for_token(user = %User{}), do: Poison.encode user
def for_token(_), do: {:error, "Unknown resource type"}
def from_token(sub) do
case Poison.decode(sub, as: %User{}) do
{:ok, user} -> {:ok, user}
{:error, _} -> {:error, "Unknown resource type"}
end
end
end
The authentication config for ExAdmin is also pretty simple:
defimpl ExAdmin.Authentication, for: Plug.Conn do
alias KCC.Router.Helpers
alias KCC.Authentication, as: Auth
def use_authentication?(_), do: true
def current_user(conn), do: Auth.current_user(conn)
def current_user_name(conn), do: Auth.current_user_name(conn)
def session_path(conn, action), do: Helpers.auth_path(conn, action)
end
defmodule KCC.Authentication do
def current_user(conn) do
Guardian.Plug.current_resource(conn)
end
def current_user_name(conn) do
conn |> current_user |> Map.get(:name)
end
end
And I haven't configured ExAdmin to discover my User model:
config :ex_admin,
repo: KCC.Repo,
module: KCC,
modules: [
KCC.ExAdmin.Dashboard
]
After logging in, I get the following error:
[error] #PID<0.488.0> running KCC.Endpoint terminated
Server: localhost:4000 (http)
Request: GET /admin
** (exit) an exception was raised:
** (UndefinedFunctionError) function KCC.User.__schema__/1 is undefined or private
(kcc) KCC.User.__schema__(:primary_key)
(ex_admin) lib/ex_admin/schema.ex:8: ExAdmin.Schema.primary_key/1
(ex_admin) lib/ex_admin/schema.ex:23: ExAdmin.Schema.get_id/1
(ex_admin) lib/ex_admin/utils.ex:201: ExAdmin.Utils.admin_resource_path/3
(ex_admin) web/templates/themes/admin_lte2/layout/header.html.eex:22: ExAdmin.AdminLte2.LayoutView."header.html"/1
(ex_admin) web/templates/layout/admin_lte2.html.eex:41: ExAdmin.LayoutView."admin_lte2.html"/1
(phoenix) lib/phoenix/view.ex:335: Phoenix.View.render_to_iodata/3
(phoenix) lib/phoenix/controller.ex:646: Phoenix.Controller.do_render/4
(ex_admin) web/controllers/admin_controller.ex:1: ExAdmin.AdminController.action/2
(ex_admin) web/controllers/admin_controller.ex:1: ExAdmin.AdminController.phoenix_controller_pipeline/2
(kcc) lib/kcc/endpoint.ex:1: KCC.Endpoint.instrument/4
(kcc) lib/phoenix/router.ex:261: KCC.Router.dispatch/2
(kcc) web/router.ex:1: KCC.Router.do_call/2
(kcc) lib/kcc/endpoint.ex:1: KCC.Endpoint.phoenix_pipeline/1
(kcc) lib/plug/debugger.ex:123: KCC.Endpoint."call (overridable 3)"/2
(kcc) lib/kcc/endpoint.ex:1: KCC.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /Users/david/Projects/nde/kcc/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
So my question is what would cause ExAdmin to be trying to discover the schema of %KCC.User{}?
The user is coming from Guardian.Plug.current_resource(conn). I suspect that its returning a simple struct and not an Ecto.Schema. Add an IO.inspect to verify.
defmodule KCC.Authentication do
def current_user(conn) do
Guardian.Plug.current_resource(conn)
|> IO.inspect # add this
end
# ...
end
If you have another schema for the user model, then you need to fetch it so the current_user above returns is.
@smpallen99 my User module is not an Ecto schema. I was able to make it look like it by added __schema__/1 to my module, but I'm wondering if ExAdmin should be requiring the current_user object to be an Ecto model?
If your up contributing a PR, you could test the current_user for __schema__ here and skip the profile menu item if its not set. Also needs to be done for the active_admin theme too.