我最初有一個這樣定義的路線:
get ':foo(/:bar)/:baz(/:qux)/:slug', to: 'application#show', constraints: { baz: /. ?\-\d / }, as: test
使用此配置,如果我:bar在路徑中省略它,它可以正常作業:
foo/baz-123/qux-quux/test
控制器回傳以下引數: {foo: 'foo', baz: 'baz-123', qux: 'qux-quux', slug: 'test'}
現在,規格改變了,我需要在baz約束中接受字母數字字符,所以我這樣做了:
get ':foo(/:bar)/:baz(/:qux)/:slug', to: 'application#show', constraints: { baz: /. ?\-[a-z0-9] / }, as: test
使用此配置,引數映射開始表現不同。相同的路徑foo/baz-123/qux-quux/test在控制器中回傳以下引數:
{foo: 'foo', bar: 'baz-123', baz: 'qux-quux', slug: 'test'}
我認為它的發生是因為也qux-quux匹配約束,所以我將其更改為/. ?\-(?=.*\d )[a-z0-9] /以確保:baz引數在-.
但是,即使qux-quxx不匹配約束,控制器仍然回傳相同的錯誤映射。
在多個可選段的情況下,Rails 如何映射引數?
uj5u.com熱心網友回復:
您的路由路徑:foo(/:bar)/:baz(/:qux)/:slug包含 5 個段、3 個必需段和 2 個可選段,因此請求路徑將在以下條件下進行驗證:
- 它包含足夠的 5 段
- 它包含 3 個部分,在這種情況下,顯然那些是 3 個強制性部分
- 它包含 4 個段,這里有 2 個有效情況:
:foo/:bar/:baz/:slug,:foo/:baz/:qux/:slug.
當您為段設定約束時,匹配器將檢查該段是否與約束匹配。正如你在前 2 個案例中看到的,匹配器知道段在哪里:baz,但是在 4 個段的情況下,匹配器必須選擇 2 個有效案例之一,所以它會混淆,因此它會一個一個檢查段,然后選擇最后一個匹配。
/. ?\-[a-z0-9] / =~ "baz-123" # matched
/. ?\-[a-z0-9] / =~ "qux-quux" # matched <-- the last one
{foo: 'foo', bar: 'baz-123', baz: 'qux-quux', slug: 'test'}
我猜約束段設定的優先級高于其他段,因此首先檢查它們,然后根據約束段位置檢查其他段,在您的情況下,:baz驗證段后,其左側的段將是:bar并且該:slug段在右側(可選段:qux將被忽略)。
當您將約束更改為 /. ?\-(?=.*\d )[a-z0-9] /
/. ?\-(?=.*\d )[a-z0-9] / =~ "baz-123" # matched <-- baz
/. ?\-(?=.*\d )[a-z0-9] / =~ "qux-quux" # not matched
# so the params should be (the `:bar` will be ignored)
{foo: 'foo', baz: 'baz-123', qux: 'qux-quux', slug: 'test'}
在我看來,:bar如果:bar和之間有任何不同的模式,最好也為段設定約束:baz,這樣匹配器會一一檢查,不再混淆。
get ':foo(/:bar)/:baz(/:qux)/:slug', to: 'application#show', constraints: {
bar: /.*/,
baz: /. ?\-(?=.*\d )[a-z0-9] /
}, as: test
我認為,另一種方法是,您可以為 segment 設定默認值:bar,并且在您的控制器中您可以處理該默認值,因此現在匹配器不會被混淆。
還有一件事,你的最后一個正則運算式/. ?\-(?=.*\d )[a-z0-9] /是greedy,這將在不考慮飛濺的情況下吞下所有路徑/,因此路徑foo/bar/baz-x/test將失敗,但路徑foo/bar/baz-x/x1x將通過,因為字符后面有一個數字-。你可以取代貪婪部分(?=.*\d )通過(?=[^\/]*\d )修復它。所以要小心正則運算式約束。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/328699.html
標籤:红宝石轨道 ruby-on-rails-5 rails-routing
