In my application, I need to add /en|es/usa|eg
to every GET route but not to be mandatory.
The first part is the locale name "en, es, ..etc", the second part is the country code "usa, eg, ..etc".
So for example, if I have:
/users/login
I can also have:
/en/usa/users/login
/es/eg/users/login
So both work together.
I tried to use scoped routes:
scope '/:locale/:country/', locale: /#{I18n.available_locales.join('|')}/, country: /#{Country::COUNTRY_CODES.join('|')}/ do
But I found this solution very error-prone, and it's so hard to decide which routes to add inside that scope.
So I tried a different approach:
In the routes.rb
file:
get "/:locale/:country_code/(*all)" => redirect(CountryLocaleRedirector.new), constraints: SeoUrlConstraint.new
In the initializers I added this class:
class CountryLocaleRedirector
def call(_params, request)
path = request.path.split('/').reject(&:blank?)
queries = request.query_string.split('&').reject(&:blank?).map{|x| x.split('=', -2)}.inject({}) do |r, s|
r.merge!({s[0] => s[1]})
end
if path[0].in?(%w[en ar])
queries[:locale] = path[0]
path = path[1..-1]
end
if path[0].in?(%w[usa eg es fr])
country = Country.find_by_country_code(path[0].upcase)
path = path[1..-1]
request.session[:country_id] = country.id if country.present?
end
"/#{path.join('/')}?#{queries.to_a.map{|x| x.join('=')}.join('&')}"
end
end
And the constraint for the route (to make it work only when the URL has locals and country codes), which I added also to the initializers:
class SeoUrlConstraint
def matches?(request)
request.path.split('/').reject(&:blank?)[0].in?(%w[kw bh ae qa sa en ar])
end
end
This is working perfectly, and when I do any GET request that has /en/usa/...
, it works but removing that from the URL (because I do redirection), and set the appropriate locales and country.
My question: Is there a way that I can stick that /en/usa/
and not remove it? Even if with monkey patching or something?
Aucun commentaire:
Enregistrer un commentaire