Criando rotas com um prefixo de caminho opcional
-
03-07-2019 - |
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
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