从下面的代码中,当我调用 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")
...
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
有人可以告诉我为什么会失败以及适当的解决方案是什么吗? TY!
最佳答案
简短回答:更改此:
params = Map.put(conn.params, "ip", "8.8.8.8")
致:
params = %{"ip": "8.8.8.8"}
说明: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"}, ... }
当您稍后调用 params["geo"]
时,Elixir 会发现 params
是一个结构体,并尝试调用 fetch/2
结构体模块上的函数,该模块不存在。要将 params
重置为普通映射(以便 Elixir 在使用方括号语法时调用 Map.get
),您只需执行 params = %{"ip": "8.8.8.8"}
.
关于struct - Plug.Conn.Unfetched 未实现 Access 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40755018/