web-dev-qa-db-ja.com

Rails現在のページへのリンクとそれにパラメータを渡す

RailsアプリケーションにURLパラメータを使用してロケールを渡すことでI18Nを追加しています。私のURLは http://example.com/en/users と- http://example.com/ar/users (それぞれ英語とアラビア語のロケール用)。

ルートファイルで、:path_prefixオプションを使用してルートを定義しました。

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

そしてロケールはApplicationControllerで定義されたbefore_filterを使用して設定されています

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

また、ApplicationController#default_url_optionsを定義して、アプリケーションによって生成されたすべてのURLにロケールを追加しました。

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

私が欲しいのは、同じページにリンクするが他のロケールにリンクするレイアウトヘッダー(すべてのページに表示される)にリンクを追加することです。

たとえば、アラビア語のロケールを参照している場合、ヘッダーに「英語」リンクを追加すると、現在のページにリダイレクトされ、ロケールが英語に設定されます。これをレールで行う方法はありますか?

48
Faisal

これを見つけるのにしばらく時間がかかりましたが、これが私の解決策です:

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

ここのドキュメントから: http://api.rubyonrails.org/classes/ActionController/Base.html#M000649

新しいURLを生成するときに、現在のリクエストのパラメーターから欠損値が入力される場合があります。たとえば、url_for:action => ‘some_action‘は、期待どおりに現在のコントローラーを保持します。この動作は、:controller、:id、およびルートのパスに配置されているその他のパラメーターを含む、その他のパラメーターにまで及びます。

したがって、url_forを使用すると、デフォルトで現在のリクエストのパラメータが使用されます。コードで必要なパラメータを変更するだけです。この場合、私が変更したのは:localeだけだったので、他はすべて同じままです。

これは「非表示」の:パラメータにも機能することに注意してください。だからあなたが持っている場合:

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

/ en/my_mapページで上記のurl_forを使用すると、URLに「home」が含まれません(つまり、/ en/home/my_map)。ボーナス。

110
pixelearth

そこで、Railsマジックに依存することなく、より明示的にこれを行う方法を見つけました。

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

これはlink_toで機能するはずです。

すべての処理は、現在のリクエストのパラメータを取得し、それらに新しい目的のハッシュをマージして、そのための新しいURLを作成することです。

14
Will

異なるロケールの現在のページへのリンク

Rails 4でテスト済み

こんにちは皆さん。しばらく研究した後、私はこのための独自のソリューションを書くことにしました。

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

これは完璧に機能しますが、以下のようにXSS Vulnerabilityを使用して、URLにパラメータを渡すだけです。

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

または最悪の場合:

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

アプリケーションでこのリンクを通過した後に取得されるURLを確認してください。

My production solution。メソッド「言語を変更」は、リクエストオブジェクトでHTTP_REFERERを使用するだけで、適切なロケールのページにリダイレクトします。 注意してください:URL全体ではなく、パスのみを取得するためのURI.pathメソッド

任意のコントローラーで「言語の変更」メソッドを作成します。

        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

これをレイアウトに追加します

<%= 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

Params.mergeやサルパッチソリューションを使用する必要はありません。

私が個人的にそれを解決するために多くの時間を費やしたので、これが役に立てば幸いです。

5
Evgeniy B

Request_uriを解析し、パス内のロケールを正規表現で置き換えることができます

さて、ここにヘルパーの例があります。目標を正しく理解していれば

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"

これは出発点なので、必要なものをいくつか作成できます

2
fl00r

DRYと適切なものではないかもしれませんが、私にとっては完全に機能します。ロケールEXのURLだけを置き換えて、指定したすべてのパラメータを読み取ります。 http ://example.com:3000/us/users?t = 123&m = 34 など

  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

はるかに迅速な手段-さまざまな場所で変化する多くのパラメーターがある場合に便利です...新しいロケールパラメーターを既存のものにマージする(そして実際には古いロケールパラメーターを強制終了する)アンカータグで混乱を避けます。

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

しかし、はい、アプリケーションのコンテキストに従って、その時点でパラメーターをホワイトリストに登録する必要があります。

0
Jerome

安全にurl_forを設定すると、only_path: trueを使用して、ロケールをparamsで切り替えることができます。

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

.clone the paramsすべてを許可する前に(.permit!)、強力なパラメーターを他の場所に保存します。私が見つけることができる唯一のより安全なソリューションは、代わりにすべてのパラメータを時間をかけてホワイトリストに登録することです...


堅牢なI18n実装:

locales.rb初期化子を追加して、サポートするI18n.available_localesを定義します。

# config/initializers/locales.rb

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

各言語のロケールファイルにlanguage_name値を設定します(例:fr.yml):

fr:
  language_name: "Français"

言語を追加すると、このERBにより、一般的にそれらを切り替えることができます。

  // 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>

コントローラーについては、ブラウザーのAccept-Language HTTPヘッダーを検出することにより、ユーザーの正しい言語を自動的に検出します( http_accept_language gemを使用)。

session Cookieを設定して、リクエスト間でロケールを保持します。

または、必要に応じて、default_url_optionsを使用して?locale=パラメータをアプリのURLに挿入します。私は両方を行います。

コントローラ:

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