Rails default_url_options 与 path/url-helpers 中的参数冲突

Rails default_url_options conflicts with params in path/url-helpers

在我的 Rails-6.1.4 应用程序中,我在 routing-filter Gem 中引入了 locale 过滤器以允许 [=52] 中的语言区域设置=]-像 /en/articles 这样的路径(对于语言环境“en”)。然后,我发现路径助手在给出 params 参数(或任何可选参数)时失败。

这是模型 Articlearticle_url() 路径助手的测试(最小测试)失败的示例,模型实例为 @article:

 # test/controllers/articles_controller_test.rb
patch article_url(@article, params: { article: my_hash })

导致

# Error output
ArticlesControllerTest#test_should_update:
DRb::DRbRemoteError: No route matches {:action=>"show", :controller=>"articles",
 :locale=>#<Article id: 805413029, ...>}, missing required keys: [:id]
 (ActionController::UrlGenerationError)
    test/controllers/articles_controller_test.rb:58:in `block in <class:ArticlesControllerTest>'

基本上,路径助手 @article 的主要参数是一个模型实例,它似乎以某种方式被路径助手解释为语言环境(!)。 我应该注意到,当 param (或其他)选项未给出时,我发现路径助手工作正常。因此,只有在给定额外参数时才会出现问题。

什么是合适的解决方案?


我的设置如下

 # test_helper.rb  (as recommended in the reference of routing-filter)
RoutingFilter.active = false

 # application_controller.rb
def default_url_options
  Rails.application.default_url_options = Rails.application.routes.default_url_options =
   { locale: I18n.locale }
end

 # config/routes.rb
Rails.application.routes.draw do
  filter :locale
  
  scope "(:locale)", locale: /en|ja|fr/ do # [EDIT] This scope should be removed;
                                           # It is unnecessary and is sometimes harmful 
                                           # as the locale in the path may be doubled. 
    resources :articles
  end
end

这里我用的是head (8d1f1da) of the master branch for routing-filter because the current RubyGems.org version (0.6.3) for it is known not to work with Rails 6.1 (see Issue 75).


事实上,我找到了一个肮脏的解决方法:

article_url(@article, {params: { article: my_hash }}.merge(
  ApplicationController.new.default_url_options))

然而,这意味着每次使用带可选参数的帮助程序时都必须编写此 Hash#merge...这在实践中会非常乏味,因为在测试套件,这当然是违反DRY原则的。

有什么解决办法吗?

简而言之,除了application_controller.rb中设置default_url_options,为了测试在config/routes.rb中设置 环境如

 # config/routes.rb
Rails.application.routes.draw do
  filter :locale
    default_url_options(locale: I18n.locale) if Rails.env.test?

这似乎是 Rails 6.1 中设置 default_url_options 的方法([编辑] application_controller.rb 中的设置仍然需要对于 development 环境;test 环境需要此设置)。这在测试和开发环境中都工作正常 除了 当在上下文之外调用路径助手时,我的意思是不是从控制器或视图中调用,在这种情况下 OP 的 肮脏的解决方法 解决了问题:

Rails.application.routes.url_helpers.article_url(
  article,
  {only_path: true}.merge(ApplicationController.new.default_url_options)
)

背景

Gem routing-filter 通过修改路径来工作,就好像路径(的头部)中包含的语言环境单词(如“en”)作为 URL 参数传递一样(如 ?locale=en),同时从路径中删除语言环境部分。所以设置default_url_options才是正确的策略。

在撰写本文时 (Rails-6.1.4),Rail's official guide 中的“从 URL 参数设置语言环境”是真的 default_url_options 设置在 app/controllers/application_controller.rb 设置默认语言环境 URL-参数。

但也许描述已过时 — 我的意思是,Rails 6.1 不再准确?

请注意,似乎 default_url_options 在 Rails 6 中引起了麻烦;参见