Plug.Conn.Unfetched不实现Access行为

ker*_*lin 3 struct runtime-error elixir phoenix-framework

从下面的代码中,当我打电话时conn.params["geo"],我收到以下错误:

test/plugs/geoip_test.exs:4
 ** (UndefinedFunctionError) function Plug.Conn.Unfetched.fetch/2 is undefined  (Plug.Conn.Unfetched does not implement the Access behaviour)
 stacktrace:
   (plug) Plug.Conn.Unfetched.fetch(%{:__struct__ => Plug.Conn.Unfetched, :aspect => :params, "geo" => "Mountain View, US", "ip" => "8.8.8.8"}, "geo")
Run Code Online (Sandbox Code Playgroud)

...

defmodule AgilePulse.Plugs.GeoIPTest do
  use AgilePulse.ConnCase

  test "returns Mountain View for 8.8.8.8" do
    conn = build_conn
    params = Map.put(conn.params, "ip", "8.8.8.8")
    conn = Map.put(conn, :params, params) |> AgilePulse.Plugs.GeoIP.call(%{})

    assert conn.params["geo"] == "Mountain View, US"
  end

end

defmodule AgilePulse.Plugs.GeoIP do
  import Plug.Conn

  def init(opts), do: opts

  def call(%Plug.Conn{params: %{"ip" => ip}} = conn, _opts) do
    geo = set_geo(ip)
    params = Map.put(conn.params, "geo", geo)
    Map.put(conn, :params, params)
  end

  def call(conn, _opts), do: conn

  ...

end
Run Code Online (Sandbox Code Playgroud)

有人可以告诉我为什么这会失败以及适当的解决方案是什么?TY!

Dog*_*ert 5

简短的回答:改变这个:

params = Map.put(conn.params, "ip", "8.8.8.8")
Run Code Online (Sandbox Code Playgroud)

至:

params = %{"ip": "8.8.8.8"}
Run Code Online (Sandbox Code Playgroud)

说明:Phoenix.ConnTest.build_conn/0返回一个Conn带有params设置为%Plug.Conn.Unfetched{}.通过使用Map.put它,您不会重置值__struct__,但只添加一个新键:

%Plug.Conn{ ...,
 params: %{:__struct__ => Plug.Conn.Unfetched, :aspect => :params,
   "ip" => "8.8.8.8"}, ... }
Run Code Online (Sandbox Code Playgroud)

当你params["geo"]稍后调用时,Elixir看到它params是一个struct,并试图fetch/2在struct的模块上调用该函数,该函数不存在.要重置params为法线贴图(以便Elixir Map.get在使用方括号语法时调用),您可以这样做params = %{"ip": "8.8.8.8"}.