Phoenix 似乎在按字母顺序和模式匹配对参数进行重新排序——这正常吗?

Phoenix seems to be re-ordering params alphabetically and pattern matching - is this normal?

这是发送请求的前端代码——注意参数的顺序:

params = {ticket_guid: "XXX-XXX", user_name: "David", quantity: 2}
$.get('/init_stripe_transaction', params, function(data) {

这是浏览器开发控制台中显示参数顺序的 "Bad Request" 数据:

http://localhost:4000/init_stripe_transaction?ticket_guid=XXX-XXX&user_name=David&quantity=2

这是终端(服务器端)的错误响应,即 phoenix elixir def 日志。注意 - 由于某些原因,参数的顺序现在如何更改:

[info] GET /init_stripe_transaction
[debug] Processing with DiceWeb.TransactionController.create_stripe_session/2

Parameters: %{"quantity" => "2", "ticket_guid" => "XXX-XXX", "user_name" => "David"}
Pipelines: [:browser]
[info] Sent 400 in 357ms
[debug] ** (Phoenix.ActionClauseError) no function clause matching in DiceWeb.TransactionController.create_stripe_session/2 

这就是我在控制器中进行模式匹配的方式:

def create_stripe_session(
  conn, 
  %{ticket_guid: ticket_guid, user_name: user_name, quantity: quantity}
) do ...

额外供参考:我对 elixir/pattern 匹配非常陌生。所以决定堆栈溢出比在 phoenix repo 上制造问题要好。这样模式匹配可以吗?

啊哇 - 显然还在思考 Ruby。

  1. 顺序无关紧要。
  2. : != => 像这样使用地图进行模式匹配时。简单地用粗箭头样式替换符号样式就解决了我的问题。无论参数的顺序如何 - 更有意义。

1) 就像在ruby中一样,地图:

%{a: 1, b: 2} 

是地图的简称:

%{:a => 1, :b => 2}

在 iex 中:

iex(1)> %{a: 1, b: 2} == %{:a => 1, :b => 2}
true

2) 在 Elixir 中,atom 不会被垃圾回收,因此 atom table 的大小有一个硬性限制,这是存储 atom 的地方. Phoenix 保护您免受有人发送 1 亿 name/value 对的请求,如果将这些请求作为 atom/value 对移交给您的应用程序,则会淹没原子 table。相反,您的控制器中的操作会收到带有 string/value 对的地图,然后您可以对其进行模式匹配以挑选出您感兴趣的 string/value 对。其余的 string/value 对将是垃圾集。按照惯例,然后将模式匹配的 key/value 对转换为 atom/value 对供内部使用,例如:

def world(conn, %{"name" => name}) do 
    render(conn, "world.html", name: name)
end 

3) 字符串不等同于原子:

iex(1)> "a" == :a
false

因此,如果一个函数的参数变量指定了一个带有键原子的映射,该函数将不会与键为字符串的映射进行模式匹配:

defmodule My do
  def go(%{:a => x}) do
    IO.puts x
  end
end

My.go(%{"a" => 10})

在命令行:

~/elixir_programs$ elixir a.exs
** (FunctionClauseError) no function clause matching in My.go/1    

    The following arguments were given to My.go/1:

        # 1
        %{"a" => 10}

    a.exs:2: My.go/1
    (elixir) lib/code.ex:767: Code.require_file/2

4) 最终,你会 运行 遇到这样的事情:

def go(%User{}) do
   ...
end

%User{} 匹配任何用户结构。