问题 从Pipeline Plug调用时,Plug.Conn.assign无法正常工作


我正在关注 凤凰城插头指南 创造我自己的 Module Plug 从会话加载当前用户。该 @user 在使用插头模块时没有分配,但是当我将其称为私有功能时,它可以正常工作 router.ex

这是我的 web/router

defmodule MyApp.Router do
  use MyApp.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug MyApp.Plugs.User
  end

  # Scopes and Routes...

end

这是我的模块(在 web/plugs/user.ex):

defmodule MyApp.Plugs.User do
  import Plug.Conn

  def init(default), do: default

  def call(conn, default) do
    user = %{
      id:       get_session(conn, :user_id),
      username: get_session(conn, :username)
    }

    assign(conn, :user, user)

    IO.inspect conn
  end
end

我试过检查它是否真的被分配,但它不是:

%Plug.Conn{adapter: {Plug.Adapters.Cowboy.Conn, :...}, assigns: %{},
 before_send: [#Function<1.75757453/1 in Plug.CSRFProtection.call/2>,
  #Function<1.30521811/1 in Phoenix.Controller.fetch_flash/2>,
  #Function<0.39713025/1 in Plug.Session.before_send/2>,
  #Function<1.7608073/1 in Plug.Logger.call/2>,
  #Function<0.72065156/1 in Phoenix.LiveReloader.before_send_inject_reloader/1>],
 body_params: %{},
 cookies: ....

12982
2018-06-23 11:31


起源



答案:


Plug.Conn.assign 返回修改后的连接。由于Elixir中的所有数据都是不可变的,因此无法修改旧数据。在你的情况下,你扔掉了结果 assign 而conn仍然指向旧的连接。你可能想要这样的东西:

conn = assign(conn, :user, user)

这将重新绑定 conn 变量指向修改后的连接结构。当然,如果 assign(conn, :user, user) 将是函数中的最后一个表达式,因为它的结果将被返回。


14
2018-06-23 11:35



我明白了...我想在进入菲尼克斯之前,我应该先得到我的Elixir基础知识。 - Sheharyar
另请注意 IO.inspect 返回它检查的值,所以 assign(conn, :user, user) |> IO.inspect 也会有效 - David Sulc


答案:


Plug.Conn.assign 返回修改后的连接。由于Elixir中的所有数据都是不可变的,因此无法修改旧数据。在你的情况下,你扔掉了结果 assign 而conn仍然指向旧的连接。你可能想要这样的东西:

conn = assign(conn, :user, user)

这将重新绑定 conn 变量指向修改后的连接结构。当然,如果 assign(conn, :user, user) 将是函数中的最后一个表达式,因为它的结果将被返回。


14
2018-06-23 11:35



我明白了...我想在进入菲尼克斯之前,我应该先得到我的Elixir基础知识。 - Sheharyar
另请注意 IO.inspect 返回它检查的值,所以 assign(conn, :user, user) |> IO.inspect 也会有效 - David Sulc