Value `"user_id"` in `where` cannot be cast to type :id in query

I am trying to work on a Role Based Access control Pheonix API. In which user will be sign in and a session will be created. After logging in he can create a post the post created will be assigned to that user_id. I have encountered this problem the user_id is coming like a string instead of the value inside it.

My router

scope "/", PxblogWeb do
    pipe_through :browser

    get "/", PageController, :index
    
    resources "/users", UserController do
      resources "/posts", PostController
    end
    
    resources "/sessions", SessionController, only: [:new, :create, :delete]
  end

  scope "/" do
    resources "/sessions", SessionController, only: [:new, :create, :delete]
  end

  # Other scopes may use custom stacks.
  scope "/api", PxblogWeb do
    pipe_through :api

    get "/users/read", UserController, :index
  end

new.html.eex

<h1>New Post</h1>
<%= render "form.html", Map.put(assigns, :action, Routes.user_post_path(@conn, :create, :user_id)) %>
<span><%= link "Back", to: Routes.user_post_path(@conn, :index, :user_id) %></span>

post_controller.ex

plug :assign_user
  plug :authorize_user when action in [:new, :create, :update, :edit, :delete]


  defp assign_user(conn, _opts) do
    case conn.params do
      %{"user_id" => user_id} ->
        case Repo.get(Pxblog.Post.User, user_id) do
          nil  -> invalid_user(conn)
          user -> assign(conn, :user, user)
        end
      _ -> invalid_user(conn)
    end
  end
  
  defp invalid_user(conn) do
    conn
    |> put_flash(:error, "Invalid user!")
    |> redirect(to: Routes.page_path(conn, :index))
    |> halt
  end

  defp authorize_user(conn, _) do
    user = get_session(conn, :current_user)
    if user && (Integer.to_string(user.id) == conn.params["user_id"] || Pxblog.RoleChecker.is_admin?(user)) do
      conn
    else
      conn
      |> put_flash(:error, "You are not authorized to modify that post!")
      |> redirect(to: Routes.page_path(conn, :index))
      |> halt()
    end
  end

  def index(conn, _params) do
    posts = Repo.all(assoc(conn.assigns[:user], :posts))
    render(conn, "index.html", posts: posts)
  end

  def new(conn, _params) do
    changeset =
      conn.assigns[:user]
      |> build_assoc(:posts)
      |> Pxblog.Learn.Post.changeset(%{})
    render(conn, "new.html", changeset: changeset)
  end

  def create(conn, %{"post" => post_params}) do
    changeset =
      conn.assigns[:user]
      |> build_assoc(:posts)
      |> Pxblog.Learn.Post.changeset(post_params)
    case Repo.insert(changeset) do
      {:ok, _post} ->
        conn
        |> put_flash(:info, "Post created successfully.")
        |> redirect(to: Routes.user_post_path(conn, :index, conn.assigns[:user]))
      {:error, changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

session_controller.ex

defmodule PxblogWeb.SessionController do
    use PxblogWeb, :controller
    
    alias Pxblog.Post.User
    alias Pxblog.Post
    alias Pxblog.Repo

    import Comeonin.Bcrypt, only: [checkpw: 2, dummy_checkpw: 0]

    plug :scrub_params, "user" when action in [:create]

    def new(conn, _params) do
      render conn, "new.html", changeset: Pxblog.Post.User.changeset(%Pxblog.Post.User{}, %{})
    end

    def create(conn, %{"user" => %{"username" => username, "password" => password}})
    when not is_nil(username) and not is_nil(password) do
      user = Repo.get_by(Pxblog.Post.User, username: username)
      sign_in(user, password, conn)
    end
    
    def create(conn, _) do
      failed_login(conn)
    end

    defp failed_login(conn) do
      dummy_checkpw()
      conn
      |> put_session(:current_user, nil)
      |> put_flash(:error, "Invalid username/password combination!")
      |> redirect(to: Routes.page_path(conn, :index))
      |> halt()
    end

    defp sign_in(user, _password, conn) when is_nil(user) do
      failed_login(conn)
    end
    
    defp sign_in(user, password, conn) do
      if checkpw(password, user.password_digest) do
        conn
        |> put_session(:current_user, %{id: user.id, username: user.username, role_id: user.role_id})
        |> put_flash(:info, "Sign in successful!")
        |> redirect(to: Routes.page_path(conn, :index))
      else
        failed_login(conn)
      end
    end

    def delete(conn, _params) do
      conn
      |> delete_session(:current_user)
      |> put_flash(:info, "Signed out successfully!")
      |> redirect(to: Routes.page_path(conn, :index))
    end

end

Hello welcome to the forum,

You are passing an atom in your route helper… are You sure it’s what You want?

In general, I don’t pass user_id in forms because I can authenticate user from within controller as conn assigns should contains current_user after successful login.

Thanks for fast response. Sorry, I am bit new. I was following a hackernoon article.

If I am not the passing the user_id atom in the function it is giving error. It is asking for three arguments even though the function def create(conn, %{"post" => post_params}) is taking two parameters only. Can you tell me where the problem is?

:wave:

Try Routes.user_post_path(@conn, :create, user_id).

Thanks for response,
It is showing error variable "user_id" does not exist.

Then maybe

<h1>New Post</h1>
<%= render "form.html", Map.put(assigns, :action, Routes.user_post_path(@conn, :create, @user)) %>
<span><%= link "Back", to: Routes.user_post_path(@conn, :index, @user) %></span>