How to use same route path for both locales - ruby-on-rails

I have this code in routes.rb.
scope ":locale", :locale => /es/ do
match "inicio" => "home#index", :as => "home"
match "acerca-de" => "about#index", :as => "about"
match "servicios" => "services#index", :as => "services"
match "blog" => "blog#index", :as => "blog"
match "contacto" => "contact#index", :as => "contact"
end
scope ":locale", :locale => /en/ do
match "home" => "home#index", :as => "home"
match "about" => "about#index", :as => "about"
match "services" => "services#index", :as => "services"
match "blog" => "blog#index", :as => "blog"
match "contact" => "contact#index", :as => "contact"
end
What I'm trying to do is have a route like /es/acerca-de and /en/about which use the same controller and have the same url_path() so when I'm at spanish language the about_path() sends you to /en/about but when I'm at english language the about_path() sends you to /es/acerca-de.

Done!
I the answer was practically in the ruby on rails guides...
This is the code in routes.rb
scope ":locale", :locale => /es|en/ do
match "inicio" => "home#index", :as => "home"
match "acerca-de" => "about#index", :as => "about"
match "servicios" => "services#index", :as => "services"
match "blog" => "blog#index", :as => "blog"
match "contacto" => "contact#index", :as => "contact"
end
and added this in application_controller
class ApplicationController < ActionController::Base
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
Saba::Application.reload_routes!
end

Related

Why default locale does not work?

In my application controller, I am forcing locale handling as a before filter:
before_filter :set_locale
def set_locale
#I18n.default_locale is en
I18n.locale = extract_locale_from_tld || I18n.default_locale
end
def extract_locale_from_tld
parsed_locale = params[:locale] || ((lang = request.env['HTTP_ACCEPT_LANGUAGE']) && lang[/^[a-z]{2}/])
#so, english is the default language.
parsed_locale= 'en' if parsed_locale.nil?
I18n.available_locales.include?(parsed_locale.to_sym) ? parsed_locale : nil
end
However, if I tried to visit http://localhost:3000/ko/lab it would result into routing error which is error 404 eventually.
Any locale out of the following locates will result into routing error:
Any advice?
EDIT
My route.er:
# -*- encoding : utf-8 -*-
MyApp::Application.routes.draw do
mount Alchemy::Engine => 'blog'
Rails.application.routes.draw do
filter :pagination, :uuid, :locale
end
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks",
:sessions => "users/sessions",
:registrations => "users/registrations"}
resources :authentications
resources :experiments
get 'experiments/:id/info_edit' => 'experiments#info_edit',:constraints => { :id => /\d+/ }
get 'sitemap.xml', :to => 'sitemap#index', :defaults => {:format => 'xml'}
match 'lang' => 'home#set_lang', :via => [:get]
#match 'free_trial' => 'home#free_trial', :via => [:get]
match 'useful_links' => 'home#useful_links', :via => [:get]
match 'home' => 'home#home', :via => [:get]
match 'contact-us' => 'contact#new', :as => 'contact_us', :via => :get
match 'contact' => 'contact#create', :as => 'contact', :via => :post
match 'dashboard' => 'experiments#index', :via => [:get]
post 'notifications' => 'subscriptions#instant_payment_notification'
match 'users_experiments' => 'experiments#users_experiments', :via => [:get]
match 'hire_us' => 'home#hire_us', :via => [:get]
get 'lab' => 'experiments#lab'
get 'experiments/:id/review-edit' => 'experiments#review', :as => :review
get 'experiments/:id/cancel-edit' => 'experiments#cancel_edit', :as => :cancel_edit
get 'experiments/:id/approve-edit' => 'experiments#approve', :as => :approve
get 'experiments/:id/reject-edit' => 'experiments#reject', :as => :reject
get 'experiments/:id/profile' => 'experiments#profile', :as => :profile
match 'amazon' => 'experiments#amazon', :via => [:get]
match 'trial_account' => 'home#trial_account', :via => [:get]
match 'student_account' => 'home#student_account', :via => [:get]
match 'school_account' => 'home#school_account', :via => [:get]
match 'create_account' => 'home#registration_redirect', :via => [:get]
match 'users/create_account' => 'home#registration_entrance', :via => [:get]
match 'registration_redirect' => 'home#registration_redirect', :via=>[:post]
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
root :to => 'home#home'
get "/auth/oauth2/callback" => "auth0#callback"
get "/auth/verification_complete" => "auth0#verification_complete"
get "/auth/failure" => "auth0#failure"
end
My server log:
Started GET "/ko/lab" for 127.0.0.1 at 2017-09-12 08:58:56 +0300
Processing by ApplicationController#routing_error as HTML
Parameters: {"path"=>"ko/lab"} User Load (202.1ms) SELECT
"users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id"
ASC LIMIT 1 [["id", 12899]] Completed 404 Not Found in 205ms ko/lab
excluded from capture: DSN not set
ActionController::RoutingError (ko/lab):
app/controllers/application_controller.rb:35:in routing_error'
lib/rack/seoredirect.rb:20:incall'
Default local does work but you don't have a route that matches /:locale/lab. Its that simple.
You can create localized routes by using scope - Rails does not do this for you.
scope '(:locale)', locale: /#{I18n.available_locales.join('|')}/ do
get '/' => 'home#home' # this will map /en to home#home
get 'lab' => 'experiments#lab'
# ...
end
This is probably a good time to refactor a really messy routes file by using the resources helper to its full extent:
resources :experiments do
member do
get :info_edit
# ...
end
end
See http://guides.rubyonrails.org/routing.html#adding-more-restful-actions

Rails constraint on route that contains dynamic segment

I have the following two routes in my Rails app:
match '/users/:username' => 'users#show', :via => :get, :as => :user
match '/users(/:filter)' => 'users#index', :via => :get, :as => :users
This is so that I can have routes like:
/users/cameron
/users/popular
Where the first is a user, and the second is a filter.
However the routing in Rails will always hit the first route, because it doesn't know the difference between :username and :filter.
For posts I avoid this problem by doing:
match '/posts/:id' => 'posts#show', :via => :get, :as => :post, :id => /[0-9]/
But this only works because posts are always integers. For example: /posts/21
How can I apply a constraint to my user routes so that they don't trip over each other and without having to add a prefix to either of them.
I've tried this approach (based on the link provided by #Mario
match '/users/:username' => 'users#show', :via => :get, :as => :user, :constraints => lambda { |request| User.usernames.include?(request.params[:username]) }
and in my User model:
def self.usernames
User.pluck(:username)
end

Rails routes with optional parameters priorities

I have an strange issue in my routes file.
This is the part that I need to understand
This routes doesn't work
# V3
# V3 - Home Page
match '/:locale' => 'v3/home#index', :constraints => V3Constraint, :as => :home
# V3 - Search
match '(/:locale)/products/search' => 'v3/products#search', :constraints => V3Constraint
# V3 - Categories index
match '(/:locale)/categories/(:parent_category((/*path)/:category))/(:full)' => 'v3/products#index', :constraints => V3Constraint, :as => :category
# V3 - Prduct Page
match '/:locale/products/:product' => 'v3/products#show', :constraints => V3Constraint, :as => :product
match '(/:locale)/search_amazon' => 'v3/products#search_amazon', :constraints => V3Constraint
# EOF V3
But this work
#V3 - Search
match '(/:locale)/products/search' => 'v3/products#search', :constraints => V3Constraint
# V3 - Categories index
match '(/:locale)/categories/(:parent_category((/*path)/:category))/(:full)' => 'v3/products#index', :constraints => V3Constraint, :as => :category
# V3 - Product Page
match '/:locale/products/:product' => 'v3/products#show', :constraints => V3Constraint, :as => :product
match '(/:locale)/search_amazon' => 'v3/products#search_amazon', :constraints => V3Constraint
# V3 - Home Page
match '/:locale' => 'v3/home#index', :constraints => V3Constraint, :as => :home
If I made the Home Page route have less priority than the others it works, but if it was on the top like the other
this route:
match '(/:locale)/search_amazon' => 'v3/products#search_amazon', :constraints => V3Constraint
will be leading to the home page.
Can any please explain why this is has to happen ?
Thanks.
Having a route like this <yourdomain>/search_amazon will match the first one of these two routes
match '(/:locale)/search_amazon' => 'v3/products#search_amazon', :constraints => V3Constraint
In this case, it will match because locale is optional here.
match '/:locale' => 'v3/home#index', :constraints => V3Constraint, :as => :home
While here it will match making search_amazon as the value for locale.

Is it possible to have different paths on the same devise model with constraints?

I'm trying to have different paths for the same devise model/resource with constraints, but the first path is the one being applied in this case "visitor".
constraints(ValidSubdomainFrontend) do
devise_for :users, :path => "visitor", :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification', :unlock => 'unblock', :registration => 'register', :sign_up => 'cmon_let_me_in' }
end
constraints(ValidSubdomainAdmin) do
devise_for :users do
get 'users', :path => "admin", :to => 'site_backend#index', :as => :user_root # Rails 3
end
devise_for :users, :controllers => { :registrations => 'users' }, :path => "admin", :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification', :unlock => 'unblock', :registration => 'register', :sign_up => 'cmon_let_me_in' }
end
Is it possible to have different paths for the same resource with Devise on different constraints?
The constraints being used are:
class ValidSubdomainAdmin
def self.matches?(request)
request.subdomain.present? &&
request.env['PATH_INFO'].start_with?('/admin')
end
end
class ValidSubdomainFrontend
def self.matches?(request)
request.subdomain.present? &&
!request.env['PATH_INFO'].start_with?('/admin')
end
end
Is this possible with Devise at all or is this a Bug?
Found the solution for this issue!
More on the context, basically needed to have something like /visitor on the front-end where users can login (to the members area) and edit their profile and other members/clients operations. But I would also want /admin where admins/editors/authors can login to the (backend) admin dashboard/area. Both areas use the same Devise model/resource (so an admin can also visit the members area). As a side note, currently I'm using CanCan permissions to prevent members from accessing the admin area.
I just had to replace the admin area constraint for:
constraints(ValidSubdomainAdmin) do
devise_scope :user do
#root :to => "devise/registrations#new"
get "admin/" => "admin#index"
post 'admin/' => 'devise/registrations#new', :as => :new_admin_registration
match 'admin/', :to => 'admin#index'
get "admin/edit" => "devise/registrations#edit"
match 'admin/edit', :to => 'devise/registrations#edit'
get "admin/login" => "devise/sessions#new", :as => :new_admin_session
match 'admin/login', :to => 'devise/sessions#new'
get "admin/logout" => "devise/sessions#destroy", :as => 'destroy_admin_session'
match 'admin/logout', :to => 'devise/sessions#destroy'
post "admin/password" => "devise/passwords#create"
get "admin/password/new" => "devise/passwords#new", :as => 'new_admin_password'
get "admin/password/edit" => "devise/passwords#edit"
put "admin/password" => "devise/passwords#update"
end
end
I also updated the views /admin/users (being used by devise on the on the admin area) to use the new admin devise paths.
Many thanks to José Valim

Ruby on Rails Routing match parameters not showing up

I have the following routes
match 'tracks/:id/entire_graph'=> "tracks#entire_graph", :as => "entire_graph"
match 'tracks/:id/entire_graph/:rid'=> "tracks#entire_graph", :as => "entire_graph2"
match 'tracks/:id/:rid' => "tracks#blahh", :as => "refer_your_friends"
resources :tracks
match '/auth/:provider/callback' => 'authentications#create'
match '/auth/failure' => 'authentications#failure'
match '/tracks/:id/:rid/facebookpost' => 'tracks#facebook_post', :as => "facebook_post_track"
match '/tracks/:id/:rid/twitterpost' => 'tracks#twitter_post', :as => "twitter_post_track"
resources :authentications
My problem is regarding the 'tracks/:id/:rid' route.
I am trying to call it like this: 'tracks/9/15'
I get a value for params[:id], but params[:rid] = nil, and I cannot figure out why.

Resources