lundi 29 janvier 2018

Adding Optional Locale and Country to Rails Routes

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