Search code examples
ruby-on-railsrails-routing

Weird path_helper error when using english locale


I am experiencing a weird error that I no longer want to work around but understand.

When recently adding an english version of our homepage, I found that I can't generate the pathes as I do for the german locale:

2.3.0 :023 > I18n.available_locales
=> [:de, :en]

2.3.0 :019 > apps_path(locale: :de)
=> "/de/apps"

2.3.0 :020 > apps_path(locale: :en)
ActionController::UrlGenerationError: No route matches 
{:action=>"apps", :controller=>"pages", :locale=>:en} missing required keys: [:locale]

As I said, I was able to work around that, by using either url_for or – when sticking with our example apps_en_path.

But I wanna know what causes this weird problem.

EDIT

A git bisect session helped me to find out that this happens since I added the route-translater gem to my project. Besides this issue it works fine for us.

I had this settings (in development.rb):

# RouteTranslator.config
config.force_locale = true
config.locale_param_key = :locale

My routes.rb:

require_relative "#{Rails.root}/app/route_constraints/can_access_devops"

Rails.application.routes.draw do
  get 'health', to: 'health#show'

  # Redirect requests with trailing 'null'
  get '/*path/null', to: redirect('/%{path}')

  namespace :admin do
    root to: redirect('/admin/magazine_articles')

    resources :jobs
    resources :users
    resources :magazine_categories
    resources :magazine_articles
    resources :media_assets
    resources :advertisements do
      member do
        get 'preview'
      end
    end

    namespace :devops do
      authenticate :user do
        constraints CanAccessDevOps do
          mount PgHero::Engine, at: '/pghero'
        end
      end
    end
  end

  scope '/:locale', locale: /#{I18n.available_locales.join("|")}/ do
    root to: 'pages#home'

    localized do
      devise_for :users, controllers: { sessions: 'sessions' }

      # redirect terms of use to cockpit; this is required because
      # the packaging has a link that should point to cockpit
      get 'home',        to: 'pages#home'
      get 'imprint',     to: 'pages#imprint', as: 'imprint'
      get 'lottery',     to: 'pages#lottery', as: 'lottery'
      get 'privacy',     to: 'pages#privacy', as: 'privacy'
      get 'terms',       to: 'pages#terms',   as: 'terms'
      get 'faq',         to: 'pages#faq',     as: 'faq'
      get 'declaration-of-conformity', to: 'pages#declaration_of_conformity', as: 'declaration_of_conformity'

      # Contact Page / Support Cases
      resource :support_cases, only: [:create, :new], path_names: { new: 'new_support_case' } do
        get :success, on: :collection
      end

      # redirect using the url helper to respect route localization. ugly but it works
      get 'kontakt', to: redirect { |_, _| Rails.application.routes.url_helpers.new_support_cases_path }

      # Workshop
      get 'workshop', to: 'pages#workshop', as: 'workshop'
      get 'autofit',  to: 'pages#autofit',  as: 'autofit'

      # App-related
      get 'app',     to: 'pages#app',     as: 'app'
      get 'apps',    to: 'pages#apps',    as: 'apps'
      get 'cars',    to: 'pages#cars',    as: 'cars'
      get 'roadmap', to: 'pages#roadmap', as: 'roadmap'

      # Press Material
      get 'press',            to: 'press_materials#index',      as: 'press_materials'
      get 'press/brand',      to: 'press_materials#brand',      as: 'press_materials_brand'
      get 'press/team',       to: 'press_materials#team',       as: 'press_materials_team'
      get 'press/app',        to: 'press_materials#app',        as: 'press_materials_app'
      get 'press/pace-link',  to: 'press_materials#pace_link',  as: 'press_materials_pace_link'
      get 'press/graphics',   to: 'press_materials#graphics',   as: 'press_materials_graphics'

      # Feature pages
      get 'features/automatic-emergency-call',  to: 'features#ecall',                as: 'ecall'
      get 'features/fuel-saving-trainer',       to: 'features#fuel_saving_trainer',  as: 'fuel_saving_trainer'
      get 'features/trouble-code-analysis',     to: 'features#trouble_code_analysis', as: 'trouble_code_analysis'
      get 'features/find-my-car',               to: 'features#find_my_car',          as: 'find_my_car'
      get 'features/logbook',                   to: 'features#logbook',              as: 'logbook'
      # old route – preserved as there might be old links somewhere pointing at this
      get 'features/automatisches-fahrtenbuch', to: 'features#automatic_logbook'
      # actual route: find-the-cheapest-gas-station
      get 'features/gas-station-finder',        to: 'features#gas_station_finder',   as: 'gas_station_finder'
      get 'features/fuel-cost-tracking',        to: 'features#fuel_cost_tracking',   as: 'fuel_cost_tracking'
      get 'features/performance-monitor',       to: 'features#performance_monitor',  as: 'performance_monitor'
      get 'features/traffic-monitor',           to: 'features#traffic_monitor',      as: 'traffic_monitor'

      # Endpoints for car finder
      get 'cars/query', to: 'cars#identify'
      get 'cars/:id',   to: 'cars#show'

      # Job adverts
      get 'jobs',        to: 'jobs#index',    as: 'jobs'
      get 'jobs/:slug',  to: 'jobs#show',     as: 'job'

      # Newsletter related routes
      post 'newsletter-sign-up',              to: 'subscribers#newsletter_create', as: 'newsletter'
      get 'newsletter-confirmation(/:list)',  to: 'subscribers#newsletter_after_confirm'
    end

    # Routes that we want to have under the german locale, but without translated route go here:

    # Magazine
    scope 'magazin' do
      get '', to: 'magazine#index', as: 'magazine', constraints: { locale: 'de' }

  # Redirect path without locale to locale equivalent path
  get '/*path', to: redirect("/#{I18n.locale}/%{path}"),
                constraints: lambda { |req|
                  !req.path.match(%r{^\/(404|422|500)$}) &&
                    !req.path.match(%r{^\/(#{I18n.available_locales.join("|")})\/.*})
                }

  # Redirect root to detected locale
  root to: 'application#redirect_to_localized_root', as: :redirected_root
end

Solution

  • I had a quick play through with your routes, and I had I similar issue with the de route. I think the apps_path route you're getting will only allow your default locale as param.

    Adding the following option solved it for me:

    RouteTranslator.config do |config|
      config.generate_unlocalized_routes = true
    end
    

    This will generate the unlocalized routes correctly, so you can pass multiple locales to apps_path.