Rails ссылается на текущую страницу и передает ей параметры
-
23-09-2019 - |
Вопрос
Я добавляю I18N в свое приложение rails, передавая локаль, используя параметры URL.Мои URL-адреса выглядят следующим образом http://example.com/en/users и http://example.com/ar/users (для английского и арабского языков соответственно).
В моем файле маршрутов я определил свои маршруты с параметром:path_prefix:
map.resources :users, :path_prefix => '/:locale'
И locale устанавливается с помощью before_filter, определенного в ApplicationController
def set_locale
I18n.locale = params[:locale]
end
Я также определил ApplicationController#default_url_options, чтобы добавить locale ко всем URL-адресам, сгенерированным приложением:
def default_url_options(options={})
{:locale => I18n.locale}
end
Что я хочу, так это добавить ссылку в заголовок макета (отображается на всех страницах), которая будет ссылаться на ту же страницу, но с другой локализацией.
Например, если я просматриваю арабскую локаль, мне нужна ссылка "English" в заголовке, которая перенаправит меня обратно на мою текущую страницу и установит локаль на английский.Есть ли способ сделать это в rails?
Решение
Мне потребовалось некоторое время, чтобы найти это, но вот мое решение:
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, так что все остальное осталось прежним.
Обратите внимание, что это также работает для параметров "hidden" :.Так что, если у вас есть:
map.my_map ':locale/my_map', :controller => 'home', :action => 'my_map'
используя указанный выше url_for на странице /en/my_map, вы не будете иметь "home" в URL (т.е. /en/home/my_map).Бонус.
Другие советы
Итак, я нашел способ сделать это более явно, не полагаясь (в такой же степени) на магию рельсов.
url_for(params.merge({:your_new_parameter => value}))
Это должно работать в любом link_to
.
Все, что он делает, это берет параметры текущего запроса и объединяет с ними ваш новый желаемый хеш, а затем создает для этого новый URL-адрес.
Ссылка на текущую страницу с разными локалями
Протестировано на Rails 4.
Всем здравствуйте.После некоторого времени исследований я решил написать для этого собственное решение.
link_to 'English', url_for( :locale => 'en' )
link_to 'Deutch', url_for( :locale => 'de' )
Это прекрасно работает, но позволяет XSS-уязвимость просто передавая параметры в ваш 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-адреса вы получите, перейдя по этой ссылке в своем приложении.
Мое производственное решение.Метод «изменить язык» перенаправляет на любую страницу с подходящей локалью, просто используя HTTP_REFERER в объекте запроса.Пожалуйста, обрати внимание:Метод URI.path для получения только пути, а не всего URL-адреса
Сделайте метод «изменить язык» в любом контроллере:
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 или какое-либо решение для обезьян.
Надеюсь, это поможет, потому что лично я потратил много времени на ее решение.
Вы можете проанализировать 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"
Это отправная точка, так что вы можете сделать что-то другое, что вам нужно.
Взгляните на это, хотя оно, может быть, и не совсем СУХОЕ, но мне подходит идеально.Он считывает все указанные вами параметры, заменяя только языковой стандарт НАПРИМЕР, 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
Гораздо более быстрый способ — и удобный, если у вас много параметров, которые меняются в разных местах…избегайте беспорядка с помощью тега привязки, который просто объединяет новый параметр локали с существующими (и фактически уничтожает старый параметр локали).
<%= link_to "ру", request.params.merge( locale: 'ru' ) %>