Pergunta

Como posso fazer minhas rotas reconhecer um parâmetro de prefixo opcional da seguinte maneira:

/*lang/controller/id

Na medida em que a parte Lang é opcional e possui um valor padrão se não for especificado no URL:

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

EDITAR

Idealmente, estou procurando fazer isso em muitos controladores e ações mapeando um espaço para nome:

map.namespace "*lang" do |lang|
  lang.resources :posts
  lang.resources :stories
end
Foi útil?

Solução

Ok, eu consegui resolver esse problema:

Não há como fazer isso em trilhos por padrão (pelo menos ainda não). Em vez de usar namespaces e valores padrão, eu precisava instalar Filtro de roteamento de Sven Fuchs.

Depois que o plug -in estiver instalado, adicionei o seguinte arquivo ao meu diretório 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

Eu adicionei esta linha para rotas.rb:

map.filter 'locale'

Isso basicamente preenche um gancho antes e depois, gerado pelo plug -in, que envolve o roteamento dos trilhos.

Quando um URL é reconhecido e antes que o Rails faça qualquer coisa com ele, o método em torno de_recognize é chamado. Isso extrairá um código de duas letras que representa o local e o passará nos parâmetros, inadimplendo para 'EN' se nenhum local for especificado.

Da mesma forma, quando um URL é gerado, o parâmetro da localidade será empurrado para o URL no lado esquerdo.

Isso me dá os seguintes URLs e mapeamentos:

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

Todos os ajudantes de URL existentes funcionam como antes, com a única diferença que, a menos que a localidade seja especificada, é preservada:

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

Outras dicas

Você pode definir padrões em uma rota usando o :defaults chave. Experimente isso:

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

Eu entendo que essa antiga pergunta, mas pode ser útil.

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

E você deve adicionar antes do filtro ao controlador de aplicativos para definir o localidade, como

before_filter :define_locale

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

Suponho (sem tempo para testar agora) que isso possa funcionar:

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

Ok, tentei - funciona, no Rails 2.1.1 pelo menos. Então isso é bom. Porém, não consigo que a ideia de padrão funcione, o que é uma pena, porque é mais secador.

Pensei que você poderia usar um momento uma [chave] => nil para especificar um parâmetro opcional. Algo como:

map.connect ':lang/posts/:id', :controller => 'posts', :action => 'show', :lang => nil
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top