Значение `" user_id "` в `где` не может быть приведено к типу: id в запросе: - PullRequest
0 голосов
/ 01 июля 2019

Я пытаюсь работать с Pheonix API управления доступом на основе ролей.В котором пользователь войдет в систему и будет создан сеанс.После входа в систему он может создать сообщение, которому будет присвоено созданное сообщение.Я столкнулся с этой проблемой, user_id идет как строка вместо значения внутри него.

Я пробовал String.to_integer (user_id), но выдает ошибку, потому что user_id идет как строка, а не какпеременная, хранящая идентификатор.

Мой маршрутизатор


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.бывший

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

1 Ответ

1 голос
/ 01 июля 2019

Ошибка в вашем названии предполагает, что где-то есть строка, которая выглядит следующим образом:

"some string user_id"

вместо:

"some string #{user_id}" 

И where в сообщении об ошибке указывает назапрос базы данных, так:

"...where id=user_id" 

вместо

"...where id=#{user_id}"

=====

В вашем действии new у вас есть:

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

Вызов render() делает переменную @changeset доступной в шаблоне (а также @conn магией эликсира).Вот ваш шаблон:

<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>

1) Вы не используете @changeset в шаблоне, поэтому указывать changeset: changeset в render () не нужно.

2) Я думаю, что вместо каждого из :user_id атомов должна быть переменная, которая содержит фактический user_id - переменную, которую вы должны создать в действии и указать в render (), как вы это сделалис changeset.

Когда вы интерполируете атом в строку (а не в переменную), вы получаете:

iex(2)> "...where user=#{:user_id}"
"...where user=user_id"

И в сообщении об ошибке говорится, что подстрока "user_id" не может быть преобразована в:id тип.Я думаю, что Phoenix должен выполнить запрос к базе данных для построения user_post_path.

. Если вы сделаете:

$ iex -S mix

, тогда:

iex(1)> h <YourApp>Web.Router.Helpers.user_post_path

def user_post_path(conn_or_endpoint, action, user_id)              
def user_post_path(conn_or_endpoint, action, user_id, params)          
def user_post_path(conn_or_endpoint, action, user_id, id, params)  

iex отображает действительные значениякоторые были созданы для вашего помощника пути.Я думаю, что если аргументом для user_id должен был быть атом :user_id, то эти функции должны были бы соответствовать шаблону на атоме, например:

def user_post_path(conn_or_endpoint, action, :user_id)              
def user_post_path(conn_or_endpoint, action, :user_id, params)          
def user_post_path(conn_or_endpoint, action, :user_id, id, params)  
...