使用可选路径前缀创建路由

时间:2008-10-17 14:39:24

标签: ruby-on-rails ruby routing

如何让路线识别可选的前缀参数,如下所示:

/*lang/controller/id

因为lang部分是可选的,并且如果未在URL中指定,则具有默认值:

/en/posts/1   => lang = en
/fr/posts/1   => lang = fr
/posts/1      => lang = en

修改

理想情况下,我希望通过映射名称空间在许多控制器和操作中执行此操作:

map.namespace "*lang" do |lang|
  lang.resources :posts
  lang.resources :stories
end

5 个答案:

答案 0 :(得分:19)

好的,我已经设法解决了这个问题:

默认情况下,无法在Rails中执行此操作(至少现在还没有)。我需要安装Sven Fuchs' routing filter

,而不是使用名称空间和默认值

安装插件后,我将以下文件添加到我的lib目录:

require 'routing_filter/base'

module RoutingFilter
  class Locale < Base

    # remove the locale from the beginning of the path, pass the path
    # to the given block and set it to the resulting params hash
    def around_recognize(path, env, &block)
      locale = nil
      path.sub! %r(^/([a-zA-Z]{2})(?=/|$)) do locale = $1; '' end
      returning yield do |params|
        params[:locale] = locale || 'en'
      end
    end

    def around_generate(*args, &block)
      locale = args.extract_options!.delete(:locale) || 'en'
      returning yield do |result|
        if locale != 'en'
          result.sub!(%r(^(http.?://[^/]*)?(.*))){ "#{$1}/#{locale}#{$2}" }
        end 
      end
    end

  end
end

我将此行添加到routes.rb:

map.filter 'locale'

这基本上填充了插件生成的前后挂钩,它包裹了rails路由。

当识别出一个url,并且在Rails开始对它做任何事情之前,会调用around_recognize方法。这将提取一个代表语言环境的双字母代码,并在params中传递它,如果没有指定语言环境,则默认为'en'。

同样,当生成url时,locale参数将被推送到左侧的URL中。

这给了我以下网址和映射:

/   => :locale => 'en'
/en => :locale => 'en'
/fr => :locale => 'fr'

所有现有的url助手都像以前一样工作,唯一的区别是除非指定了区域设置,否则它将被保留:

home_path                  => /
home_path(:locale => 'en') => /
home_path(:locale => 'fr') => /fr

答案 1 :(得分:2)

您可以使用:defaults键定义路线中的默认值。试试这个:

map.connect ':lang/posts/:id', :controller => 'posts', :action => 'show',
                               :defaults => { :lang => 'en' }

答案 2 :(得分:2)

我理解这个老问题,但它可能有用。

  map.with_options(:path_prefix => ":locale") do |m|
    m.resources :posts
    m.resources :stories        
  end

您必须在过滤器之前添加到应用程序控制器以定义区域设置,例如

before_filter :define_locale

def define_locale
  if params[:locale] == nil
    I18n.locale = 'en'
  else
    I18n.locale = params[:locale]
  end
end

答案 3 :(得分:1)

我猜测(现在没时间测试)这可能有用:

map.connect ':language/posts/:id', :controller => 'posts', :action => 'show'
map.connect 'posts/:id', :controller => 'posts', :action => 'show'

好的,尝试过 - 它至少可以在Rails 2.1.1上运行。这很好。然而,无法获得:默认的想法,这是一种耻辱,因为它是DRYer。

答案 4 :(得分:1)

以为你可以一次使用[key] =&gt; nil指定可选参数。类似的东西:

map.connect ':lang/posts/:id', :controller => 'posts', :action => 'show', :lang => nil