I have and app with a users controller and I want to have it as a toplevel path in my routes, like:
get ':id' => 'users#show', as: :user_profile
and my to_param method in User is:
def to_param
self.username
end
So that when you hit "/rodrigo" for example, it will look for the User object with the username = "rodrigo". So far, so good.
But I also have some static pages that I want to have toplevel paths as well, such as about, terms,
controller :home do
get 'about', to: :about, as: 'about'
get 'help', to: :help, as: 'help'
get 'terms', to: :terms, as: 'terms'
get 'privacy', to: :privacy, as: 'privacy'
end
what happens is that when I try to access any of these static pages I get:
NoMethodError in Users#show
Showing /Users/rodrigovieira/Code/golaco/app/views/users/show.html.erb where line #1 raised:
undefined method `name' for nil:NilClass
Also, my users#show routes is defined before the static pages routes in routes.rb.
that is, Rails thinks I'm talking about a user object. How can I circumvent this problem?
I'm pretty sure it's possible. I appreciate any help.
Rails routes are matched in the order they are specified, so if you have a resources :photos above a get 'photos/poll' the show action's route for the resources line will be matched before the get line. To fix this, move the get line above the resources line so that it is matched first.
Golaco::Application.routes.draw do
# Institutional/Static pages
controller :home do
get 'about', to: :about, as: 'about'
get 'help', to: :help, as: 'help'
get 'terms', to: :terms, as: 'terms'
get 'privacy', to: :privacy, as: 'privacy'
end
get ':id' => 'users#show', as: :user_profile
resources :users, path: "/", only: [:edit, :update]
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
root 'home#index'
end
Related
So a few people have had this problem, but none of their code actually matches mine so their solutions aren't working.
Basically, whenever I try to access /users/:id it passes in the params correctly {'id' => '1'}, but then the page errors out on 'no user with id='sign_out'
My routes:
Rails.application.routes.draw do
devise_for :users, path: 'devise'
get 'sessions/new'
get 'intro', to: 'index#intro'
root 'index#intro'
authenticated :user do
root 'index#homepage', as: :authenticated_root
end
devise_scope :user do
get '/start', to: 'devise/sessions#new', as: "login"
get '/devise/sign_out', to: 'devise/sessions#destroy', as: "logout"
get '/signup', to: 'users#new', as: "signup"
end
get '/forgotPassword', to: 'index#forgotPassword'
get '/homepage', to: 'index#homepage'
get '/meetUs', to: 'index#meetUs'
get '/makeSuggestion', to: 'index#makeSuggestion'
get 'profile', to: 'index#profile'
resources :suggestions
resources :rewards
resources :users
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Code in controller erroring out:
# GET /users/1
# GET /users/1.json
def show
#users = User.find(params[:id])
end
I'm pretty sure the issue has something to do with the routes thinking /users is both a resource of mine and of devise. But I don't know how to tell it to use the default route rails made as opposed to the one devise made.
If anyone could help, and try and explain why it's happening, that'd be great. Thanks in advance!
edit: Picks of the error and trace
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
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.
There is nothing that looks super suspicious to me except this localized block. Does this come from some gem? If so does the apps_path(locale: 'en') request work outside of this localized block?
You can use Rails.application.routes.url_helpers.app_path(locale: :en) on the console to test this after adjusting the routes file.
I want to replace the normal /users/:id route that is created by the resources command, with a more abstract /profile route. It won't be possible to view other users profiles in my app, and therefor the current route is unnecessary specific.
I have tried to overwrite the route created by 'resources :users' with:
get '/profile', to: 'users#show'
and other variances and combinations, but can't seem to get it right. Either the controller can't find the user because of a missing id or it simply can't find the route.
Thanks for the help!
You can use this code in routes.rb file:
resources :users, :except => :show
collection do
get 'profile', :action => 'show'
end
end
It will generate url "/users/profile".
But, if u want to use only '/profile', then don't create route as collection inside users resources block.
resources :users, :except => :show
get 'profile' => "users#show", :as => :user_profile
It will redirect '/profile' to show action in users controller.
I suggest simply adding a users/me route pointing to the show action of your UsersController like so:
resources :users, only: [] do
collection do
get 'me', action: :show
end
end
You can also use the match keyword in routes.rb file.
match 'users/:id' => 'users#show', as: :user_profile, via: :get
I asked this question earlier and thought it was fixed, but it's not. Previous question here
My problem is I am trying to set my routes so that when I type in
localhost:3000/sites/admin
It should redirect to
localhost:3000/en/sites/admin
here is my routes.rb file
scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do
get "log_out" => "sessions#destroy", as: "log_out"
get "log_in" => "sessions#new", as: "log_in"
resources :sites, except: [:new, :edit, :index, :show, :update, :destroy, :create] do
collection do
get :home
get :about_us
get :faq
get :discounts
get :services
get :contact_us
get :admin
get :posts
end
end
resources :users
resources :abouts
resources :sessions
resources :coupons
resources :monthly_posts
resources :reviews
resources :categories do
collection { post :sort }
resources :children, :controller => :categories, :only => [:index, :new, :create, :new_subcategory]
end
resources :products do
member do
put :move_up
put :move_down
end
end
resources :faqs do
collection { post :sort }
end
root :to => 'sites#home'
match "/savesort" => 'sites#savesort'
end
match '', to: redirect("/#{I18n.default_locale}")
match '*path', to: redirect("/#{I18n.default_locale}/%{path}")
But as of right now, it redirects to /en/en/en/en/en/en/en/en/en/en/sites/admin (adds en until browser complains).
Any thoughts why it keeps adding /en?
Edit:
The answer is great, thanks. Can you help me diagnose the root route?
root to: redirect("#{/#{I18n.default_locale}") # handles /
I know redirects is looking for something like
redirect("www.example.com")
So that leaves this part
#{/#{I18n.default_locale}
The #{ is using rubys string interpolation, right? i'm not sure what that { is doing though.
So then we have
/#{I18n.default_locale}
Which is also using string interpolation and to print out the value of I18n.default_locale?
Hopefully that makes sense, I really really appreciate the help, I am learning a lot.
Edit 2:
I changed the line from
root to: redirect("#{/#{I18n.default_locale}") # handles /
to
root to: redirect("/#{I18n.default_locale}") # handles /
But i'm not sure if thats right. Now i'm getting the error
uninitialized constant LocaleController
I know it's getting the error from the root to: "locale#root", but i thought the locale# would come from the scope.
I'll continue playing with it and let you know any progress.
Here is a new link to my routes file https://gist.github.com/2332198
We meet again, ruevaughn. :)
I created a test rails app and the following minimal example works for me:
scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do
resources :sites do
collection do
get :admin
end
end
root to: "locale#root" # handles /en/
match "*path", to: "locale#not_found" # handles /en/fake/path/whatever
end
root to: redirect("/#{I18n.default_locale}") # handles /
match '*path', to: redirect("/#{I18n.default_locale}/%{path}") # handles /not-a-locale/anything
When using Rails 4.0.x that %{path} in the redirect will escape slashes in the path, so you will get an infinite loop redirecting to /en/en%2Fen%2Fen%2Fen...
Just in case someone, like me, is looking for a Rails-4-suitable solution, this is what I found to be working without problems, even with more complex paths to be redirected:
# Redirect root to /:locale if needed
root to: redirect("/#{I18n.locale}", status: 301)
# Match missing locale paths to /:locale/path
# handling additional formats and/or get params
match '*path', to: (redirect(status: 307) do |params,request|
sub_params = request.params.except :path
if sub_params.size > 0
format = sub_params[:format]
sub_params.except! :format
if format.present?
"/#{I18n.locale}/#{params[:path]}.#{format}?#{sub_params.to_query}"
else
"/#{I18n.locale}/#{params[:path]}?#{sub_params.to_query}"
end
else
"/#{I18n.locale}/#{params[:path]}"
end
end), via: :all
# Redirect to custom root if all previous matches fail
match '', to: redirect("/#{I18n.locale}", status: 301), via: :all
I am trying to implement internationalization as seen in railscasts, and every time I scope my routes file I get the error
No route matches [GET] "/"
or the error
missing :controller
config/routes.rb:6:in `block (2 levels) in <top (required)>'
config/routes.rb:5:in `block in <top (required)>'
config/routes.rb:1:in `<top (required)>'
Here is my routes.rb file
Jensenlocksmithing::Application.routes.draw do
get "log_out" => "sessions#destroy", as: "log_out"
get "log_in" => "sessions#new", as: "log_in"
scope ":locale" do
get "site/home"
get "site/about_us"
get "site/faq"
get "site/discounts"
get "site/services"
get "site/contact_us"
get "site/admin"
get "site/posts"
root :to => 'site#home'
end
#match '*path', to: redirect("/#{I18n.default_locale}/%{path}")
#match '', to: redirect("/#{I18n.default_locale}")
match "/savesort" => 'site#savesort'
resources :users
resources :abouts
resources :sessions
resources :coupons
resources :monthly_posts
resources :reviews
resources :categories do
collection { post :sort }
resources :children, :controller => :categories, :only => [:index, :new, :create, :new_subcategory]
end
resources :products do
member do
put :move_up
put :move_down
end
end
resources :faqs do
collection { post :sort }
end
end
So, why whenever I add the scope ":locale" do end line do I get these errors? It all works fine without. Let me know if you need to see any more code. Thanks guys
Edit
In my application controller I have the following:
private
def default_url_options(options = {})
{locale: I18n.locale}
end
Does this do the same thing as the passing the hash in the routes?
Edit 2
I changed my route to the following as seen in this gist.
https://gist.github.com/2322844
So why is the :id part being added to the get route? like this one
about_us_site GET /sites/:id/about_us(.:format)
shouldn't it be something like this
about_us_site GET /sites/about_us(.:format)
Also added my entire routes.rb file and the routes it generates for more information.
https://gist.github.com/2322861
Answer for anyone interested:
I changed
get "site/home"
get "site/about_us"
get "site/faq"
get "site/discounts"
get "site/services"
get "site/contact_us"
get "site/admin"
get "site/posts"
root :to => 'site#home'
to
resources :sites, except: [:new, :edit, :index, :show, :update, :destroy, :create] do
collection do
get :home
get :about_us
get :faq
get :discounts
get :services
get :contact_us
get :admin
get :posts
end
end
Passing in a hash should fix your routes:
scope "(:locale)", :defaults => { :locale => "en" } do
resources :sites
end
Also, you may want to consider creating a SitesController and giving it members:
resources :sites do
member do
get :about_us # Points to /sites/about_us
end
end
Rails Guides on Defining Defaults In Routes