【问题标题】:Rails default_url_options conflicts with params in path/url-helpersRails default_url_options 与 path/url-helpers 中的参数冲突
【发布时间】:2021-08-18 00:36:07
【问题描述】:

在我的 Rails-6.1.4 应用程序中,我在 routing-filter Gem 中引入了 locale 过滤器,以允许在 URL 路径中使用语言区域设置,例如 /en/articles(对于区域设置“en”)。然后,当给定params 参数(或任何可选参数)时,我发现路径助手会失败。

以下是模型Article 的模型实例为@articlearticle_url() 路径助手测试失败的示例(minitest):

 # 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 进行路由过滤,因为已知当前的RubyGems.org version (0.6.3) 不适用于Rails 6.1(请参阅Issue 75)。


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

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

但是,这意味着每次使用带有可选参数的辅助函数时都必须编写此 Hash#merge……这在实践中会非常乏味,因为测试套件中可能有成百上千个这样的句子,并且这当然是违反 DRY 原则的。

有什么办法吗?

【问题讨论】:

    标签: ruby-on-rails internationalization locale ruby-on-rails-6 rails-i18n


    【解决方案1】:

    简而言之,除了application_controller.rb中设置default_url_options,在test环境中设置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 中的设置仍然是 开发 环境所必需的; 测试 环境需要此设置)。这在测试和开发环境中都可以正常工作除了,当路径助手在上下文之外调用时,我的意思是不是从控制器或视图中调用,在这种情况下,OP 的 dirty 解决方法 解决了这个问题:

    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 中造成了问题;见Set locale via default_url_options for Rails tests (Rails 6 and newer)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-01
      • 1970-01-01
      • 2016-08-12
      • 1970-01-01
      相关资源
      最近更新 更多