2008-10-17 7 views
22

Comment puis-je de faire mes itinéraires reconnaissent un paramètre de préfixe optionnel comme suit:Création d'itinéraires avec un préfixe de chemin facultatif

/*lang/controller/id 

que la partie lang est facultative, et a une valeur par défaut si elle n'est pas spécifié dans l'URL:

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

EDIT

Idéalement, je cherche à le faire à travers de nombreux contrôleurs et actions en cartographiant une namespace:

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

Dans votre exemple, vous faites référence à seulement 1 contrôleur, mais je suppose que vous voulez créer cet itinéraire pour chaque manette? –

Répondre

19

OK, je l'ai réussi à régler ce problème:

Il n'y a pas moyen de le faire dans Rails par défaut (au moins, pas encore). Au lieu d'utiliser les espaces de noms et les valeurs par défaut, j'avais besoin d'installer Sven Fuchs' routing filter.

Une fois le plugin installé, j'ai ajouté le fichier suivant dans mon répertoire 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 

J'ai ajouté cette ligne à routes.rb:

map.filter 'locale' 

Cela remplit essentiellement un avant et après le crochet, généré par le plugin, qui enveloppe le cheminement des rails.

Lorsqu'une URL est reconnue et avant que Rails ne puisse faire quoi que ce soit, la méthode around_recognize est appelée. Cela va extraire un code à deux lettres représentant les paramètres régionaux, et le transmettre dans les paramètres, par défaut à 'en' si aucun paramètre régional n'est spécifié.

De même, quand une URL est générée, le paramètre locale sera poussé dans l'URL sur le côté gauche.

Cela me donne les urls et les correspondances suivantes:

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

Tous les assistants d'URL existants fonctionnent comme avant, avec la seule différence étant que si les paramètres régionaux est spécifié, il est conservé:

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

Merci pour le conseil, cela a bien fonctionné pour certains travaux de traduction/localisation/internationalisation 'Je fais. Pour info, vous n'avez pas besoin d'ajouter ce fichier à votre bibliothèque - le filtre 'locale' est déjà inclus dans le plugin. Tout ce que vous devez faire est: 1. Installez le plugin. 2. Ajoutez 'map.filter 'locale'' à votre routes.rb. Après cela, il commence juste à travailler! Agréable. J'ai également ajouté 'RoutingFilter :: Locale.include_default_locale = false' à mon environnement.rb pour éviter que'/fr' ne se trouve dans mes liens. Fonctionne très bien, j'espère que le plugin Sven sera tiré dans la base de code Rails I18n. –

+1

Voici une autre option que j'ai parcourue aujourd'hui, que je n'ai pas examinée (le routing-filter fonctionne bien) mais qui pourrait intéresser les autres: http://github.com/raul/translate_routes –

+0

Toutes les idées pour traduire ceci dans Rails3? – dgilperez

1

Je devine (pas de temps à tester en ce moment) que cela pourrait fonctionner:

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

OK, il a essayé - ça marche, on Rails 2.1.1 au moins. Donc c'est bien. Impossible de faire fonctionner l'idée: defaults, ce qui est dommage, parce que c'est DRYer.

2

Vous pouvez définir des valeurs par défaut dans un itinéraire à l'aide de la touche :defaults. Essayez ceci:

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

Ne fonctionne pas dans 2.1.1 sur ma machine. http: // localhost: 3000/posts/1 donne Aucune route correspond "/ posts/1" avec {: method =>: get} Ressemble à: les paramètres par défaut ne fournissent que des paramètres qui ne se trouvent pas dans la route? Je dois enquêter: je ne savais pas: par défaut du tout, alors merci! –

+0

Je pense que c'est sur la bonne voie - est-il possible d'intégrer cette option avec des espaces de noms et des ressources? – Codebeef

+1

IIRC, les valeurs par défaut fonctionnent comme les valeurs par défaut dans les paramètres de la méthode - ie les valeurs par défaut ne peuvent être utilisées que sur les dernières valeurs listées dans l'ordre, et non sur les premières valeurs –

1

Vous pensiez que vous pouviez utiliser une [clé] => nil pour spécifier un paramètre facultatif. Quelque chose comme:

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

Je comprends que cette vieille question, mais il peut être utile.

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

Et vous devez ajouter avant filtre au contrôleur d'application pour définir locale, tels que

before_filter :define_locale 

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

Le préfixe de chemin d'accès n'est pas facultatif. Par conséquent, vous devez toujours indiquer un paramètre régional à moins que vous ne dupliquiez les routes en dehors du bloc. – dseifert

Questions connexes