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

时间:2010-03-30 07:50:59

标签: ruby-on-rails internationalization

我通过使用url params传递语言环境,将I18N添加到我的rails应用程序中。我的网址看起来像http://example.com/en/usershttp://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

我想要的是在布局标题中添加一个链接(显示在所有页面中),该链接将链接到同一页面,但链接到另一个区域设置。

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

8 个答案:

答案 0 :(得分:109)

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

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

来自此处的文档:http://api.rubyonrails.org/classes/ActionController/Base.html#M000649

  

生成新网址时,丢失   价值可以从中填写   当前请求的参数。对于   例如,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)。奖金。

答案 1 :(得分:14)

所以我找到了一种更明确地做到这一点的方法,而不依赖于(同样多)rails magic。

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

这适用于任何link_to

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

答案 2 :(得分:5)

使用不同区域设置链接到当前页面

在Rails 4上进行了测试

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

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

这非常有效,但它只允许 XSS漏洞在您的网址中传递参数,如下所示:

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

在您的应用程序中查看此链接后,查看您将获得哪些网址。

我的生产解决方案。 方法"改变语言"使用请求对象中的HTTP_REFER重定向到具有适当区域设置的任何页面。 请注意:仅获取路径的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') %>
  

配置/ routes.rb中

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

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

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

答案 3 :(得分:2)

您可以解析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"

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

答案 4 :(得分:1)

看看这个,虽然它可能不是干的和正确的,但对我来说很完美。它读取您提供的所有参数,仅替换区域设置 EX urls: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

答案 5 :(得分:0)

更快的途径-如果您有许多在不同地方更改的参数,这将非常方便...避免使用带有将新的语言环境参数合并到现有语言环境参数(实际上是杀死旧的语言环境参数)的锚标记的混乱情况

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

答案 6 :(得分:0)

如果您设置了url_for,则可以safely使用params来切换URL为only_path: true的语言环境:

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

我们.clone 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

答案 7 :(得分:0)

这对我有用,它保留了参数并防止了xss:

= link_to_unless_current "English", url_for( request.params.merge(locale: 'en'))

您可以使用link_to代替link_to_unless_current