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

问题描述 投票:0回答:2

在我的 Rails-6.1.4 应用程序中,我在

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

这是在模型

article_url()
Article
路径助手上测试(最小测试)失败的演示示例,模型实例为
@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

这里我使用 master 分支的 head (8d1f1da) 作为路由过滤器,因为当前的 RubyGems.org 版本 (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
2个回答
1
投票

简而言之,除了在default_url_options

设置
application_controller.rb
之外,在
config/routes.rb
中为test环境设置为

 # 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 官方指南中的“从 URL 参数设置区域设置”确实表明了这一点

default_url_options
设置于
app/controllers/application_controller.rb
设置默认区域设置 URL 参数。

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

注意,似乎

default_url_options
在 Rails 6 中造成了麻烦;请参阅 通过 Rails 测试的 default_url_options 设置区域设置(Rails 6 及更高版本)


0
投票

我在 Rails 7 中找到了解决这个问题的方法,而无需废弃路由文件。通过在

config/environments/test.rb
中设置,可以使控制器和集成测试正常工作:

Rails.application.routes.default_url_options[:locale] = I18n.default_locale

或者将其设置为

test_helper.rb
:

class ActiveSupport::TestCase
  setup do
    Rails.application.routes.default_url_options[:locale] = I18n.default_locale
  end

就我而言,在上下文之外(即不在控制器或视图中)调用路径助手的唯一问题是在邮件程序中。在这种情况下,我只需在

config/environments/test.rb
中的操作邮件程序 default_url_options 中设置区域设置:

config.action_mailer.default_url_options = { host: host, protocol: 'http', locale: :en }

最后,控制器/集成测试的解决方案都不适用于系统测试。为了解决这个问题,我将其添加到

application_system_test_case.rb
:

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  ...

  setup do
    default_url_options[:locale] = I18n.default_locale
  end
© www.soinside.com 2019 - 2024. All rights reserved.