web-dev-qa-db-fra.com

Rails lien vers la page en cours et passage de paramètres à celle-ci

J'ajoute I18N à mon Rails application en passant les paramètres régionaux à l'aide des paramètres d'URL. Mes URL ressemblent à http://example.com/en/users et - http://example.com/ar/users (pour les paramètres régionaux anglais et arabe respectivement).

Dans mon fichier de routes, j'ai défini mes routes avec une option: path_prefix:

map.resources :users, :path_prefix => '/:locale'

Et les paramètres régionaux sont définis à l'aide d'un before_filter défini dans ApplicationController

def set_locale
    I18n.locale = params[:locale]
end

J'ai également défini ApplicationController # default_url_options, pour ajouter des paramètres régionaux à toutes les URL générées par l'application:

def default_url_options(options={})
    {:locale => I18n.locale}
end

Ce que je veux, c'est ajouter un lien dans l'en-tête de mise en page (affiché dans toutes les pages) qui serait lié à la même page mais avec les autres paramètres régionaux.

Par exemple, si je parcours les paramètres régionaux arabes, je veux un lien "anglais" dans l'en-tête, qui me redirigera vers ma page actuelle et définira les paramètres régionaux sur anglais. Y a-t-il un moyen de le faire dans les rails?

48
Faisal

Cela m'a pris un certain temps pour trouver cela, mais voici ma solution:

link_to 'English', url_for( :locale => 'en' )
link_to 'Deutch', url_for( :locale => 'de' ) 

De la documentation ici: http://api.rubyonrails.org/classes/ActionController/Base.html#M000649

Lors de la génération d'une nouvelle URL, les valeurs manquantes peuvent être remplies à partir des paramètres de la demande actuelle. Par exemple, url_for: action => ‘some_action’ conservera le contrôleur actuel, comme prévu. Ce comportement s’étend à d’autres paramètres, notamment: contrôleur,: id et tout autre paramètre placé dans le chemin d’une route.

Donc, en utilisant url_for par défaut, les paramètres de la requête en cours, il suffit de changer celui que vous voulez dans votre code. Dans ce cas, tout ce que j'ai changé était: locale, donc tout le reste reste le même.

Notez que cela fonctionne également pour les paramètres "cachés": Donc si vous avez:

map.my_map ':locale/my_map', :controller => 'home', :action => 'my_map'

utiliser l'url_for ci-dessus dans la page/en/my_map n'aura pas 'home' dans l'url (ie/en/home/my_map). Prime.

110
pixelearth

J'ai donc trouvé un moyen de le faire de manière plus explicite sans compter sur (autant) Rails magic.

url_for(params.merge({:your_new_parameter => value}))

Cela devrait fonctionner dans n'importe quel link_to.

Tout ce qu'il fait, c'est prendre les paramètres de la requête actuelle et y fusionner le nouveau hachage souhaité, puis créer une nouvelle URL pour cela.

14
Will

Lien vers la page actuelle avec différents paramètres régionaux

Testé sur Rails 4

Bonjour à tous. Après un certain temps de recherche, je décide d'écrire ma propre solution pour cela.

link_to 'English', url_for( :locale => 'en' )
link_to 'Deutch', url_for( :locale => 'de' ) 

Cela fonctionne parfaitement, mais il permet Vulnérabilité XSS juste en passant des paramètres dans votre URL comme ci-dessous:

http://localhost:3000/en/about?host=www.fishingsiteorbadurl.com/%23&port=80

Ou pire cas:

http://localhost:3000/en/about?host=%D0%BE%D1%87%D0%B5%D0%BD%D1%8C%D0%BF%D0%BB%D0%BE%D1%85%D0%BE%D0%B9%D1%81%D0%B0%D0%B9%D1%82.%D1%80%D1%84

Découvrez les URL que vous obtiendrez après avoir parcouru ce lien dans votre application.

Ma solution de production. La méthode "changer de langue" redirige vers n'importe quelle page avec les paramètres régionaux appropriés en utilisant simplement HTTP_REFERER dans l'objet de demande. Remarque: méthode URI.path pour obtenir uniquement le chemin, pas l'URL entière

Créez une méthode de "changement de langue" dans n'importe quel contrôleur:

        def change_lang

        if request.referer.nil?
                 refer = root_url
        else
                 uri = URI(request.referer)
                 refer = uri.path
        end
        lang = params[:lang]
        cookies[:locale] = lang
        redirect_to refer

        end

application_controller.rb

before_action :set_locale

def set_locale

# -- Get lang from cookies or url parameter locale

user_locale = cookies[:locale] || params[:locale]

# -- If present

if user_locale.present? 

    # -- If it is has 2 symbols

    user_locale = user_locale.scan(/[a-zA-Z]{2}/) 
else

    # -- If no - use default en locale

    user_locale = 'en'
end


# -- Check, is this locale available for using.
# Please note: this needed for disable invalid locale warning.

if I18n.available_locales.include?(user_locale[0].to_sym)

    I18n.locale =  user_locale[0]
else
    I18n.locale =   "en"
end

end

ajoutez ceci à votre mise en page

<%= link_to 'English', change_lang_path('en') %> <%= link_to 'Russian', change_lang_path('ru') %>

config/routes.rb

scope "(:locale)", locale: /[a-zA-Z]{2}/ do
get "change_lang/:lang" => "users#change_lang", :as => "change_lang"
end

Il n'est pas nécessaire d'utiliser params.merge ou une solution de patch de singe.

J'espère que cela aide, car j'ai personnellement passé beaucoup de temps à le résoudre.

5
Evgeniy B

Vous pouvez analyser request_uri et remplacer vos paramètres régionaux dans le chemin par une expression régulière

Ok, voici un exemple d'aide. Si je comprends bien l'objectif

def locale_url(url, locale)
  url.gsub(/\/\w*$/, "/#{locale}")
end

url = "http://www.domain.com/products/1/ru" # or request.request_uri
locale = "en"
locale_url(url, locale) #=> "http://www.domain.com/products/1/en"

Ceci est un point de départ, vous pouvez donc faire des choses différentes dont vous avez besoin

2
fl00r

Jetez un oeil à cela, bien qu'il ne soit pas DRY et un bon, mais fonctionne parfaitement pour moi. Il lit tous les paramètres que vous avez fournis en remplaçant uniquement les URL EX locales: http : //example.com: 3000/us/users? t = 123 & m = 34 etc

  def us_link           
        link_to "US", form_locale_url("/us")            
  end

  def jp_link           
    link_to "Japan",form_locale_url("/jp")           
  end              

  def form_locale_url(locale)            
    new_url = request.request_uri          
    new_locale_url = new_us_url = new_jp_url = new_url           
    if new_url == "/"          
      new_locale_url.sub!(/\//,locale)           
    elsif (new_url =~/\/us/) == 0        
      new_us_url.sub!(/\/us/,locale)        
    elsif (new_url =~/\/jp/) == 0          
      new_jp_url.sub!(/\/jp/,locale)       
    end     
  end
1
Santosh Bt

Une avenue beaucoup plus rapide - et pratique si vous avez de nombreux paramètres qui changent à différents endroits ... évitez l'encombrement avec une balise d'ancrage qui fusionne simplement le nouveau paramètre de paramètres régionaux aux paramètres existants (et en fait, tue l'ancien paramètre de paramètres régionaux).

<%= link_to "ру", request.params.merge( locale: 'ru' ) %>

Mais oui, il faut ajouter des paramètres à la liste blanche à ce stade, selon le contexte de l'application.

0
Jerome

Vous pouvez en toute sécurité utiliser url_for pour changer de locale avec l'url params si vous définissez only_path: true:

<%= link_to I18n.t('language_name', locale: I18n.locale), url_for( params.clone.permit!.merge(locale: locale, only_path: true ) %>

Nous .clone le params avant de les autoriser tous (.permit!), pour conserver des paramètres forts ailleurs. La seule solution plus sûre que je pourrais trouver serait de chronométrer la liste blanche de tous les paramètres à la place ...


Implémentation I18n robuste:

Ajouter un locales.rb initialiseur pour définir ce que I18n.available_locales vous soutenez:

# config/initializers/locales.rb

# Permitted locales available for the application
I18n.available_locales = [:en, :fr]

Définissez un language_name valeur dans le fichier de paramètres régionaux de chaque langue (par exemple, fr.yml):

fr:
  language_name: "Français"

Au fur et à mesure que vous ajoutez des langues, cet ERB vous permet de basculer entre elles de manière générique:

  // app/views/layouts/_languages.html.erb
  <span class="languages">
   <% I18n.available_locales.each do |locale| %>
      <% if I18n.locale == locale %>
        <%= link_to I18n.t('language_name', locale: locale), url_for( params.clone.permit!.merge(locale: locale, only_path: true ), {style: "display:none" } %>
      <% else %>
        <%= link_to I18n.t('language_name', locale: locale), url_for( params.clone.permit!.merge(locale: locale, only_path: true ) %>
      <% end %>
    <% end %>
  </span>

Pour le contrôleur, nous trouvons automatiquement la langue correcte pour l'utilisateur en détectant le navigateur de son Accept-Language En-tête HTTP (en utilisant la gemme http_accept_language ).

Définissez un cookie session pour conserver les paramètres régionaux entre les demandes.

Ou, facultativement, utilisez default_url_options pour insérer le ?locale= param dans l'URL de votre application. Je fais les deux.

Manette:

class ApplicationController < ActionController::Base
  before_action :set_locale

  private

  def set_locale
    I18n.locale = begin
      extract_locale ||
        session[:locale] ||
          http_accept_language.compatible_language_from(I18n.available_locales) ||
            I18n.default_locale
    end
    session[:locale] = I18n.locale
  end

  def extract_locale
    parsed_locale = params[:locale].dup
    I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
  end

  def default_url_options
    { locale: I18n.locale }
  end
end
0
Kelsey Hannan