在 Rails 4 中使用范围路由的默认值总是覆盖 default_url_options

Using defaults values for scoped route in Rails 4 always overrides default_url_options

我正在尝试在现有应用程序的 url 中实现 可选 "region" 参数:

现有: /博客

新: /se/blogs 或者 /en/blogs

这条路线应该是可选的(它只会用作过滤器,没有区域意味着世界范围内),参数值应该是 'ww' (世界范围内)或 nil (或其他任何东西,如只要我知道 none 已提供)。

我想出的路线是这样的:

scope "(:region)", region: /en|se|dk|no|ww/, defaults: {region: 'ww'} 

我在 ApplicationController 中使用 default_url_options 将 :region 参数设置为与 param[:region] 相同,以便它在存在时被保留并且应该添加到所有 urls在页面上。

def default_url_options(options={})
  { region: params[:region] }
end

问题是,当我使用 url /se/blogs 时,参数被正确设置为 'se' 但它没有被添加到页面上的任何 url自动地。如果我删除作用域路由的默认选项,它会工作并在参数前面加上参数 'se' 但是随后,因为没有默认值,许多 urls 失败并显示 'ActionController::UrlGenerationError: No route matches' 因为在 url helper 对象正在获取区域值,因为没有默认值。

关于如何解决这个问题有什么想法吗?它可能与这个(仍未解决的)问题有关吗? https://github.com/rails/rails/issues/12178

我希望保留您现有的路线 /blogs,并添加一个名为 region 或其他名称的可选参数。

所以 url 就像 /blogs?region=se/blogs?region=en

然后在您的 controller 中,您只需要根据 params[:region]

应用不同的代码

更简单,更稳定的 url 结构。

以这种方式设置默认区域似乎不起作用;但是,根据指南,它应该:

http://guides.rubyonrails.org/routing.html#defining-defaults

如果 nil 是可接受的值,为什么不放弃默认值?

config/routes.rb

scope "(:region)", region: /en|se|dk|no|ww/ do
  resources :blogs
end

作为解决方法,您可以像这样设置默认区域:

app/controllers/application_controller.rb

def default_url_options(options={})
  { region: params[:region] || "ww" }
end

更新:

没有默认区域:

config/routes.rb

scope "(:region)", region: /en|se|dk|no/ do
  resources :blogs do
    resources :posts
  end
end

app/controllers/application_controller.rb

def default_url_options(options={})
  { region: params[:region] }
end

在您看来:

<% @blog.posts.each do |post|
  <%= link_to post.title, blog_post_path(@blog, post) %>
<% end %>

URL 未指定区域时:

/blogs/1/posts/1

URL 当指定 en 区域时:

/en/blogs/1/posts/1

更新#2:

好的,我能够重现您的失败测试。这是由 Rails 错误引起的,它与您在问题中提到的错误相同。您可以在此处阅读有关此问题和一些解决方法的更多信息:

https://github.com/rspec/rspec-rails/issues/255

为了让您的测试通过,一种方法是使用 before(:all) 块初始化 default_url_options 中的 region 选项。尝试将以下内容添加到您的 RSpec 配置中:

spec/rails_helper.rb

RSpec.configure do |config|
  config.before(:each) do
    default_url_options[:region] = nil
  end
end

您可能希望将该块限制为 featurecontroller 组类型。

希望对您有所帮助。