I am trying to make a site on which users can login and see there information and possibly even change that information. I already made it so that everything CRUD wise works (that is for admin users) however I try to now make it so that users can see their own profile but i keep getting this error:
Phoenix.ActionClauseError at GET /users/1 no function clause matching in DieterDierenWeb.UserController.show/2
The following arguments were given to DieterDierenWeb.UserController.show/2:
# 1
%Plug.Conn{adapter: {Plug.Cowboy.Conn, :...}, assigns: %{}, before_send: [#Function<0.78923111/1 in Plug.CSRFProtection.call/2>, #Function<2.106486136/1 in Phoenix.Controller.fetch_flash/2>, #Function<0.55231287/1 in Plug.Session.before_send/2>, #Function<0.93523768/1 in Plug.Telemetry.call/2>, #Function<0.126770172/1 in Phoenix.LiveReloader.before_send_inject_reloader/3>], body_params: %{}, cookies: %{"Idea-3e8c4776" => "3b04f3fa-aa86-4c82-99aa-67afd963f87b", "_auth_web_key" => "SFMyNTY.g3QAAAACbQAAAAtfY3NyZl90b2tlbm0AAAAYdlktVkpOcndMeHduMW9BRURvTlpsR0pRbQAAABZndWFyZGlhbl9kZWZhdWx0X3Rva2VubQAAAUxleUpoYkdjaU9pSklVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKaGRXUWlPaUpoZFhSb1gzZGxZaUlzSW1WNGNDSTZNVFU1T0RRM056Y3pOQ3dpYVdGMElqb3hOVGsyTURVNE5UTTBMQ0pwYzNNaU9pSmhkWFJvWDNkbFlpSXNJbXAwYVNJNklqY3pZV1ppTjJRMExXVTNNRGN0TkRrNVpDMDROR015TFdVME9ERXpaREJrTXpJd05pSXNJbTVpWmlJNk1UVTVOakExT0RVek15d2ljM1ZpSWpvaU15SXNJblI1Y0NJNkltRmpZMlZ6Y3lKOS5tbjJDSkZ2VFNZSFNTd0cwaERaMUhjQ2RrSk1Od1ltTlEyUWZvQkNVV0NnUEhCbmVLeHBMbks0ZkVoX3hZS1ZEZmxtUzlZU24xMWFKR0RkbnNRQ1M1UQ.3CIxsqM_P0nRQDemm87hTX6wX5Exs0cITllQc3Z6EBk", "_dieter_dieren_web_key" => "SFMyNTY.g3QAAAACbQAAAAtfY3NyZl90b2tlbm0AAAAYX1R2cGUyNXM0dmdTUENYV1B0R2hEUnQzbQAAABZndWFyZGlhbl9kZWZhdWx0X3Rva2VubQAAAWRleUpoYkdjaU9pSklVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKaGRXUWlPaUprYVdWMFpYSmZaR2xsY21WdVgzZGxZaUlzSW1WNGNDSTZNVFU1T0RRNE1qTXdNQ3dpYVdGMElqb3hOVGsyTURZek1UQXdMQ0pwYzNNaU9pSmthV1YwWlhKZlpHbGxjbVZ1WDNkbFlpSXNJbXAwYVNJNklqSXlNamd6TUdObExURmhPVGN0TkdZMU5TMDVNMkpoTFRJMk56UXlabUkyTWpBMFpDSXNJbTVpWmlJNk1UVTVOakEyTXpBNU9Td2ljM1ZpSWpvaU1TSXNJblI1Y0NJNkltRmpZMlZ6Y3lKOS51REFYaXNnbEFFV0xFcVc5cmwtLUdSZlQyRkRzaHhJc2l3OUZ4QU11Y2NuVTM5TF9IX2dmRWxmbDZFTnN2ME1UUzJhN1hwemo2UXZIN2NfT2xUMk1Edw.vhYfhv6S2-X_bwDRnfYxHBhb20bZgDHg74VWbAx3RYw", "locale" => "en"}, halted: false, host: "localhost", method: "GET", owner: #PID<0.550.0>, params: %{"user_id" => "1"}, path_info: ["users", "1"], path_params: %{"user_id" => "1"}, port: 4000, private: %{DieterDierenWeb.Router => {[], %{}}, :guardian_default_claims => %{"aud" => "dieter_dieren_web", "exp" => 1598482300, "iat" => 1596063100, "iss" => "dieter_dieren_web", "jti" => "222830ce-1a97-4f55-93ba-26742fb6204d", "nbf" => 1596063099, "sub" => "1", "typ" => "access"}, :guardian_default_resource => %DieterDieren.UserContext.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, hashed_password: "$pbkdf2-sha512$160000$Bg04EMgtWjNcElFqKbWyWw$riiymuaNwzg1dDl/UL4PMpUffNdblCAlbgWSWkUdRf0ei9M4KOGG/YUnY0m87MpbhbSk7wI0SG/JunGJtGaM3g", id: 1, password: nil, role: "User", username: "user"}, :guardian_default_token => "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJkaWV0ZXJfZGllcmVuX3dlYiIsImV4cCI6MTU5ODQ4MjMwMCwiaWF0IjoxNTk2MDYzMTAwLCJpc3MiOiJkaWV0ZXJfZGllcmVuX3dlYiIsImp0aSI6IjIyMjgzMGNlLTFhOTctNGY1NS05M2JhLTI2NzQyZmI2MjA0ZCIsIm5iZiI6MTU5NjA2MzA5OSwic3ViIjoiMSIsInR5cCI6ImFjY2VzcyJ9.uDAXisglAEWLEqW9rl--GRfT2FDshxIsiw9FxAMuccnU39L_H_gfElfl6ENsv0MTS2a7Xpzj6QvH7c_OlT2MDw", :guardian_error_handler => DieterDierenWeb.ErrorHandler, :guardian_module => DieterDierenWeb.Guardian, :phoenix_action => :show, :phoenix_controller => DieterDierenWeb.UserController, :phoenix_endpoint => DieterDierenWeb.Endpoint, :phoenix_flash => %{}, :phoenix_format => "html", :phoenix_layout => {DieterDierenWeb.LayoutView, :app}, :phoenix_router => DieterDierenWeb.Router, :phoenix_view => DieterDierenWeb.UserView, :plug_session => %{"_csrf_token" => "_Tvpe25s4vgSPCXWPtGhDRt3", "guardian_default_token" => "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJkaWV0ZXJfZGllcmVuX3dlYiIsImV4cCI6MTU5ODQ4MjMwMCwiaWF0IjoxNTk2MDYzMTAwLCJpc3MiOiJkaWV0ZXJfZGllcmVuX3dlYiIsImp0aSI6IjIyMjgzMGNlLTFhOTctNGY1NS05M2JhLTI2NzQyZmI2MjA0ZCIsIm5iZiI6MTU5NjA2MzA5OSwic3ViIjoiMSIsInR5cCI6ImFjY2VzcyJ9.uDAXisglAEWLEqW9rl--GRfT2FDshxIsiw9FxAMuccnU39L_H_gfElfl6ENsv0MTS2a7Xpzj6QvH7c_OlT2MDw"}, :plug_session_fetch => :done}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %{"Idea-3e8c4776" => "3b04f3fa-aa86-4c82-99aa-67afd963f87b", "_auth_web_key" => "SFMyNTY.g3QAAAACbQAAAAtfY3NyZl90b2tlbm0AAAAYdlktVkpOcndMeHduMW9BRURvTlpsR0pRbQAAABZndWFyZGlhbl9kZWZhdWx0X3Rva2VubQAAAUxleUpoYkdjaU9pSklVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKaGRXUWlPaUpoZFhSb1gzZGxZaUlzSW1WNGNDSTZNVFU1T0RRM056Y3pOQ3dpYVdGMElqb3hOVGsyTURVNE5UTTBMQ0pwYzNNaU9pSmhkWFJvWDNkbFlpSXNJbXAwYVNJNklqY3pZV1ppTjJRMExXVTNNRGN0TkRrNVpDMDROR015TFdVME9ERXpaREJrTXpJd05pSXNJbTVpWmlJNk1UVTVOakExT0RVek15d2ljM1ZpSWpvaU15SXNJblI1Y0NJNkltRmpZMlZ6Y3lKOS5tbjJDSkZ2VFNZSFNTd0cwaERaMUhjQ2RrSk1Od1ltTlEyUWZvQkNVV0NnUEhCbmVLeHBMbks0ZkVoX3hZS1ZEZmxtUzlZU24xMWFKR0RkbnNRQ1M1UQ.3CIxsqM_P0nRQDemm87hTX6wX5Exs0cITllQc3Z6EBk", "_dieter_dieren_web_key" => "SFMyNTY.g3QAAAACbQAAAAtfY3NyZl90b2tlbm0AAAAYX1R2cGUyNXM0dmdTUENYV1B0R2hEUnQzbQAAABZndWFyZGlhbl9kZWZhdWx0X3Rva2VubQAAAWRleUpoYkdjaU9pSklVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKaGRXUWlPaUprYVdWMFpYSmZaR2xsY21WdVgzZGxZaUlzSW1WNGNDSTZNVFU1T0RRNE1qTXdNQ3dpYVdGMElqb3hOVGsyTURZek1UQXdMQ0pwYzNNaU9pSmthV1YwWlhKZlpHbGxjbVZ1WDNkbFlpSXNJbXAwYVNJNklqSXlNamd6TUdObExURmhPVGN0TkdZMU5TMDVNMkpoTFRJMk56UXlabUkyTWpBMFpDSXNJbTVpWmlJNk1UVTVOakEyTXpBNU9Td2ljM1ZpSWpvaU1TSXNJblI1Y0NJNkltRmpZMlZ6Y3lKOS51REFYaXNnbEFFV0xFcVc5cmwtLUdSZlQyRkRzaHhJc2l3OUZ4QU11Y2NuVTM5TF9IX2dmRWxmbDZFTnN2ME1UUzJhN1hwemo2UXZIN2NfT2xUMk1Edw.vhYfhv6S2-X_bwDRnfYxHBhb20bZgDHg74VWbAx3RYw", "locale" => "en"}, req_headers: [{"accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"}, {"accept-encoding", "gzip, deflate"}, {"accept-language", "nl,en-US;q=0.7,en;q=0.3"}, {"connection", "keep-alive"}, {"cookie", "Idea-3e8c4776=3b04f3fa-aa86-4c82-99aa-67afd963f87b; locale=en; _dieter_dieren_web_key=SFMyNTY.g3QAAAACbQAAAAtfY3NyZl90b2tlbm0AAAAYX1R2cGUyNXM0dmdTUENYV1B0R2hEUnQzbQAAABZndWFyZGlhbl9kZWZhdWx0X3Rva2VubQAAAWRleUpoYkdjaU9pSklVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKaGRXUWlPaUprYVdWMFpYSmZaR2xsY21WdVgzZGxZaUlzSW1WNGNDSTZNVFU1T0RRNE1qTXdNQ3dpYVdGMElqb3hOVGsyTURZek1UQXdMQ0pwYzNNaU9pSmthV1YwWlhKZlpHbGxjbVZ1WDNkbFlpSXNJbXAwYVNJNklqSXlNamd6TUdObExURmhPVGN0TkdZMU5TMDVNMkpoTFRJMk56UXlabUkyTWpBMFpDSXNJbTVpWmlJNk1UVTVOakEyTXpBNU9Td2ljM1ZpSWpvaU1TSXNJblI1Y0NJNkltRmpZMlZ6Y3lKOS51REFYaXNnbEFFV0xFcVc5cmwtLUdSZlQyRkRzaHhJc2l3OUZ4QU11Y2NuVTM5TF9IX2dmRWxmbDZFTnN2ME1UUzJhN1hwemo2UXZIN2NfT2xUMk1Edw.vhYfhv6S2-X_bwDRnfYxHBhb20bZgDHg74VWbAx3RYw; _auth_web_key=SFMyNTY.g3QAAAACbQAAAAtfY3NyZl90b2tlbm0AAAAYdlktVkpOcndMeHduMW9BRURvTlpsR0pRbQAAABZndWFyZGlhbl9kZWZhdWx0X3Rva2VubQAAAUxleUpoYkdjaU9pSklVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKaGRXUWlPaUpoZFhSb1gzZGxZaUlzSW1WNGNDSTZNVFU1T0RRM056Y3pOQ3dpYVdGMElqb3hOVGsyTURVNE5UTTBMQ0pwYzNNaU9pSmhkWFJvWDNkbFlpSXNJbXAwYVNJNklqY3pZV1ppTjJRMExXVTNNRGN0TkRrNVpDMDROR015TFdVME9ERXpaREJrTXpJd05pSXNJbTVpWmlJNk1UVTVOakExT0RVek15d2ljM1ZpSWpvaU15SXNJblI1Y0NJNkltRmpZMlZ6Y3lKOS5tbjJDSkZ2VFNZSFNTd0cwaERaMUhjQ2RrSk1Od1ltTlEyUWZvQkNVV0NnUEhCbmVLeHBMbks0ZkVoX3hZS1ZEZmxtUzlZU24xMWFKR0RkbnNRQ1M1UQ.3CIxsqM_P0nRQDemm87hTX6wX5Exs0cITllQc3Z6EBk"}, {"host", "localhost:4000"}, {"upgrade-insecure-requests", "1"}, {"user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0"}], request_path: "/users/1", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "FiZa8vmBNwA5UtgAAAOh"}, {"x-frame-options", "SAMEORIGIN"}, {"x-xss-protection", "1; mode=block"}, {"x-content-type-options", "nosniff"}, {"x-download-options", "noopen"}, {"x-permitted-cross-domain-policies", "none"}, {"cross-origin-window-policy", "deny"}], scheme: :http, script_name: [], secret_key_base: :..., state: :unset, status: nil}
# 2
%{"user_id" => "1"}
Despite this being fully possible through admin resources (see below).
This is my router file (as you can see there is also an admin scope with resources and i can indeed do this properly as admin by just going to /admin/users/1:
> defmodule DieterDierenWeb.Router do use DieterDierenWeb, :router
>
> pipeline :browser do
> plug :accepts, ["html"]
> plug :fetch_session
> plug :fetch_flash
> plug :protect_from_forgery
> plug :put_secure_browser_headers end
>
> pipeline :api do
> plug :accepts, ["json"] end
>
> pipeline :auth do
> plug DieterDierenWeb.Pipeline end
>
> pipeline :ensure_auth do
> plug Guardian.Plug.EnsureAuthenticated end
>
> pipeline :allowed_for_users do
> plug DieterDierenWeb.Plugs.AuthorizationPlug, ["Admin", "User"] end
>
> pipeline :allowed_for_admins do
> plug DieterDierenWeb.Plugs.AuthorizationPlug, ["Admin"] end
>
> scope "/", DieterDierenWeb do
> pipe_through [:browser, :auth]
>
> get "/", SessionController, :new
> get "/login", SessionController, :new
> post "/login", SessionController, :login
> get "/logout", SessionController, :logout
> get "/users/new", UserController, :show_sign_up
> post "/users/new", UserController, :sign_up end
>
> scope "/", DieterDierenWeb do
> pipe_through [:browser, :auth, :ensure_auth, :allowed_for_users]
>
> get "/users/:user_id", UserController, :show
> get "/user_scope", PageController, :user_index end
>
> scope "/admin", DieterDierenWeb do
> pipe_through [:browser, :auth, :ensure_auth, :allowed_for_admins]
>
> resources "/users", UserController end # Other scopes may use custom stacks. # scope "/api", DieterDierenWeb do # pipe_through
> :api # end end
This is my controller file the show function should show the profile page on the basis of the currently logged in user but here it gives the error:
defmodule DieterDierenWeb.UserController do
use DieterDierenWeb, :controller
alias DieterDieren.UserContext
alias DieterDieren.UserContext.User
def index(conn, _params) do
users = UserContext.list_users()
render(conn, "index.html", users: users)
end
def new(conn, _params) do
changeset = UserContext.change_user(%User{})
roles = UserContext.get_acceptable_roles()
render(conn, "new.html", changeset: changeset, acceptable_roles: roles)
end
def show_sign_up(conn, _params) do
changeset = UserContext.change_user(%User{})
roles = UserContext.get_acceptable_roles()
render(conn, "sign_up.html", changeset: changeset, acceptable_roles: roles)
end
def create(conn, %{"user" => user_params}) do
case UserContext.create_user(user_params) do
{:ok, user} ->
conn
|> put_flash(:info, "User created successfully.")
|> redirect(to: Routes.user_path(conn, :show, user))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
def sign_up(conn, %{"user" => user_params}) do
case UserContext.create_user(user_params) do
{:ok, user} ->
conn
|> put_flash(:info, "User created successfully, please login to your new account.")
|> redirect(to: Routes.session_path(conn, :new))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "sign_up.html", changeset: changeset)
end
end
def show(conn, %{"id" => id}) do
user = UserContext.get_user!(id)
render(conn, "show.html", user: user)
end
def edit(conn, %{"id" => id}) do
user = UserContext.get_user!(id)
changeset = UserContext.change_user(user)
roles = UserContext.get_acceptable_roles()
render(conn, "edit.html", user: user, changeset: changeset, acceptable_roles: roles)
end
def update(conn, %{"id" => id, "user" => user_params}) do
user = UserContext.get_user!(id)
case UserContext.update_user(user, user_params) do
{:ok, user} ->
conn
|> put_flash(:info, "User updated successfully.")
|> redirect(to: Routes.user_path(conn, :show, user))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "edit.html", user: user, changeset: changeset)
end
end
def delete(conn, %{"id" => id}) do
user = UserContext.get_user!(id)
{:ok, _user} = UserContext.delete_user(user)
conn
|> put_flash(:info, "User deleted successfully.")
|> redirect(to: Routes.user_path(conn, :index))
end
end
I will also give you the nav I use to try and navigate to the profile page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title><%= assigns[:page_title] || "DieterDieren · Phoenix Framework" %></title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<%= csrf_meta_tag() %>
</head>
<body>
<header>
<section class="container">
<nav role="navigation">
<ul>
<li><a href=#>日本語</a></li>
<li><a href=#>Nederlands</a></li>
<li><a href=#>English</a></li>
</ul>
<%= if Guardian.Plug.authenticated?(@conn, []) do%>
<ul>
<li><a href=#>Overzicht</a></li>
<li><a href=#>My profile</a></li>
<li><a href="<%= Routes.session_path(@conn, :logout) %>">Logout</a></li>
<%= if checkAdmin(@conn) == true do%>
<li><a href="<%= Routes.user_path(@conn, :index) %>">User management</a></li>
<% end %>
</ul>
<% end %>
</nav>
</section>
</header>
<main role="main" class="container">
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<%= render @view_module, @view_template, assigns %>
</main>
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</body>
</html>
Since I am quite new to this and since it says the first parameter is from my plug I will also give you the plug file no idea if this is helpfull or not though:
defmodule DieterDierenWeb.Plugs.AuthorizationPlug do
import Plug.Conn
alias DieterDieren.UserContext.User
alias Phoenix.Controller
def init(options), do: options
def call(%{private: %{guardian_default_resource: %User{} = u}} = conn, roles) do
conn
|> grant_access(u.role in roles)
end
def grant_access(conn, true), do: conn
def grant_access(conn, false) do
conn
|> Controller.put_flash(:error, "Unauthorized access")
|> Controller.redirect(to: "/")
|> halt
end
end
Can anyone please help me find my error?