Ruby-on-rails Rails 链接到当前页面并将参数传递给它

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2543576/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:28:24  来源:igfitidea点击:

Rails link to current page and passing parameters to it

ruby-on-railsinternationalization

提问by Faisal

I am adding I18N to my rails application by passing the locale using url params. My urls are looking like http://example.com/en/usersand http://example.com/ar/users(for the english and arabic locales respectively).

我通过使用 url 参数传递语言环境将 I18N 添加到我的 rails 应用程序中。我的网址看起来像http://example.com/en/usershttp://example.com/ar/users(分别用于英语和阿拉伯语语言环境)。

In my routes file, I have defined my routes with a :path_prefix option:

在我的路由文件中,我使用 :path_prefix 选项定义了我的路由:

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

And locale is being set using a before_filter defined in ApplicationController

并且使用 ApplicationController 中定义的 before_filter 设置语言环境

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

I also defined ApplicationController#default_url_options, to add locale to all urls generated by the application:

我还定义了 ApplicationController#default_url_options,为应用程序生成的所有 url 添加语言环境:

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

What I want is to add a link in the layout header (displayed in all pages) that would link to the same page but with the other locale.

我想要的是在布局标题(显示在所有页面中)中添加一个链接,该链接将链接到同一页面但使用其他语言环境。

For instance, if I am browsing the arabic locale, I want a "English" link in the header, that will redirect me back to my current page, and set the locale to english. Is there a way to do this in rails?

例如,如果我正在浏览阿拉伯语语言环境,我希望在标题中有一个“英语”链接,这会将我重定向回当前页面,并将语言环境设置为英语。有没有办法在rails中做到这一点?

回答by pixelearth

Took me a while to find this but here is my solution:

我花了一段时间才找到这个,但这是我的解决方案:

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

From the docs here: http://api.rubyonrails.org/classes/ActionController/Base.html#M000649

从这里的文档:http: //api.rubyonrails.org/classes/ActionController/Base.html#M000649

When generating a new URL, missing values may be filled in from the current request‘s parameters. For example, url_for :action => ‘some_action‘ will retain the current controller, as expected. This behavior extends to other parameters, including :controller, :id, and any other parameters that are placed into a Route‘s path.

生成新 URL 时,可能会从当前请求的参数中填充缺失值。例如, url_for :action => 'some_action' 将按预期保留当前控制器。此行为扩展到其他参数,包括 :controller、:id 以及放置在 Route 路径中的任何其他参数。

So using url_for will default to the current request's parameters, just change the one's you want in your code. In this case all I changed was :locale, so everything else stays the same.

因此,使用 url_for 将默认为当前请求的参数,只需在代码中更改您想要的参数即可。在这种情况下,我只更改了 :locale,因此其他所有内容都保持不变。

Note this also works for "hidden" :parameters. So if you have:

请注意,这也适用于“隐藏”:参数。所以如果你有:

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

using the above url_for in the page /en/my_map will not have 'home' in the url (ie /en/home/my_map). Bonus.

在页面 /en/my_map 中使用上述 url_for 将不会在 url 中包含“home”(即 /en/home/my_map)。奖金。

回答by Will

So I found a way to more explicitly do this with out relying on (as much) rails magic.

所以我找到了一种更明确地做到这一点的方法,而无需依赖(尽可能多的)rails 魔法。

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

This should work in any link_to.

这应该适用于任何link_to.

All its doing is taking the current request's parameters and merging your new desired hash into them and then creating a new url for that.

它所做的就是获取当前请求的参数并将新的所需散列合并到它们中,然后为此创建一个新的 url。

回答by Evgeniy B

Link to current page with different locales

链接到具有不同语言环境的当前页面

Tested on Rails 4

在 Rails 4 上测试

Hello all. After some time of research I decide to write my own solution for this.

大家好。经过一段时间的研究,我决定为此编写自己的解决方案。

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

This works perfect, but it allows XSS Vulnerabilityjust passing parameters in your URL like below:

这很完美,但它允许XSS 漏洞仅在您的 URL 中传递参数,如下所示:

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

Or worst case:

或者最坏的情况:

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

Check out what URLs you will get after going through this link in your application.

查看在您的应用程序中通过此链接后您将获得哪些 URL。

My production solution.Method "change language" redirects to any page with proper locale just using HTTP_REFERER in request object. Please note: URI.path method for get only path, not whole url

我的生产解决方案。方法“更改语言”重定向到任何具有适当语言环境的页面,只需在请求对象中使用 HTTP_REFERER。 请注意:URI.path 方法只获取路径,而不是整个 url

Make "change language" method in any controller:

在任何控制器中制作“更改语言”方法:

        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

应用控制器.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

add this to your layout

将此添加到您的布局

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

config/routes.rb

配置/路由.rb

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

There is no need to use params.merge or any monkey-patch solution.

不需要使用 params.merge 或任何猴子补丁解决方案。

I hope this helps, because I personally spent a lot of time to solve it.

我希望这会有所帮助,因为我个人花了很多时间来解决它。

回答by Jerome

A much quicker avenue - and convenient if you have many parameters that change in different places... avoid the clutter with an anchor tag that just merges the new locale param to the existing ones (and actually killing the old locale param).

一条更快的途径 - 如果您有许多在不同地方发生变化的参数,那么方便......避免使用锚标记将新的语言环境参数合并到现有的混乱(实际上杀死旧的语言环境参数)。

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

But yes, one needs to whitelist parameters at that point, according to application's context.

但是,是的,根据应用程序的上下文,此时需要将参数列入白名单。

回答by fl00r

You can parse request_uri, and replace your locale in the path with regular expression

您可以解析 request_uri,并用正则表达式替换路径中的语言环境

Ok, here is helper example. If I correctly understand the goal

好的,这是助手示例。如果我正确理解目标

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"

This is a start point, so you can make some different stuff that you need

这是一个起点,所以你可以制作一些你需要的不同的东西

回答by Santosh Bt

Have a look at this, though it may not be DRY and proper one, but works perfectly for me. It reads all the parameters you supplied replacing only the locale EX urls : http://example.com:3000/us/users?t=123&m=343etc

看看这个,虽然它可能不是 DRY 和适当的,但对我来说非常适合。它读取您提供的所有参数,仅替换区域设置 EX url:http: //example.com: 3000/us/users?t=123&m= 343

  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

回答by Kelsey Hannan

You can safelyuse url_forto switch locales with url paramsif you set only_path: true:

如果您设置,您可以安全地使用url_forurl 切换语言环境:paramsonly_path: true

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

We .clonethe paramsbefore permitting them all (.permit!), to preserve strong parameters elsewhere. The only more secure solution I could find would be to time consumingly whitelist all params instead...

我们.cloneparams允许他们所有的(前.permit!),在其他地方保持强劲的参数。我能找到的唯一更安全的解决方案是耗时地将所有参数列入白名单......



Robust I18n implementation:

健壮的 I18n 实现:

Add a locales.rbinitializer to define what I18n.available_localesyou support:

添加一个locales.rb初始化程序来定义I18n.available_locales您支持的内容:

# config/initializers/locales.rb

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

Set a language_namevalue in each language's locale file (e.g. fr.yml):

language_name在每种语言的语言环境文件中设置一个值(例如fr.yml):

fr:
  language_name: "Fran?ais"

As you add more languages, this ERB will let you generically switch between them:

随着您添加更多语言,此 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>

For the controller, we automatically find the correct language for the user by detecting their browser's Accept-LanguageHTTP header (using the http_accept_languagegem).

对于控制器,我们通过检测用户浏览器的Accept-LanguageHTTP 标头(使用http_accept_languagegem)自动为用户找到正确的语言。

Set a sessioncookie to preserve locale across requests.

设置sessioncookie 以跨请求保留区域设置。

Or optionally, use default_url_optionsto insert the ?locale=param into your app's url. I do both.

或者(可选)用于default_url_options?locale=参数插入到您的应用程序的 url 中。我两者都做。

Controller:

控制器:

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