RoutingError (No route matches [PUT] - ruby-on-rails-3
Im having an issue with regard my routes. Im using devise but I also have custom controllers to allow admins to edit user settings.
In my case, everything works fine in development but when i deploy to my hosting server things dont work as they should.
Problem i have is as follows, when an admin updates a user, i get a routing error. This works fine locally but on the hosting server i get the following
Started PUT "/users/4" at Fri Feb 21 04:08:14 -0500 2014
ActionController::RoutingError (No route matches [PUT] "/4"):
actionpack (3.2.2) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'> actionpack (3.2.2) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call'
railties (3.2.2) lib/rails/rack/logger.rb:26:in `call_app'
railties (3.2.2) lib/rails/rack/logger.rb:16:in `call'
actionpack (3.2.2) lib/action_dispatch/middleware/request_id.rb:22:in `call'
What doesnt look right to me, is how the "/users/4" gets stripped down to "/4". What happened to the rest of the path?
My routes look fine
users POST /users(.:format) users/registrations#create
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) users/registrations#cancel
user_registration POST /users(.:format) users/registrations#create
new_user_registration GET /users/sign_up(.:format) users/registrations#new
edit_user_registration GET /users/edit(.:format) users/registrations#edit
PUT /users(.:format) users/registrations#update
DELETE /users(.:format) users/registrations#destroy
new_user_session GET /users/sign_in(.:format) devise/sessions#new
POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
POST /users/password(.:format) devise/passwords#create
GET /users/password/new(.:format) devise/passwords#new
GET /users/password/edit(.:format) devise/passwords#edit
PUT /users/password(.:format) devise/passwords#update
GET /users/cancel(.:format) devise/registrations#cancel
POST /users(.:format) devise/registrations#create
GET /users/sign_up(.:format) devise/registrations#new
GET /users/edit(.:format) devise/registrations#edit
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
As you can see the user update path exists
PUT /users/:id(.:format) users#update
The host server is using passenger, rails 3.2.X, ruby 1.8.7. I´m aware there is security issues with the 3.2.x version but this is just a hobby of mine.
Routes config
resources :comm_channels
devise_for :users, :controllers => { :registrations => "users/registrations" } do
post '/users', :to => 'users/registrations#create'
end
devise_for :users
resources :users,:roles,:news ,:invites, :clubs, :events, :albums, :pictures, :static_pages, :sponsors
match "static_pages/:action/:pagetype", :controller => "static_pages"
match 'invites/edit(/:eid/:iid/:code)' => 'invites#edit', :as => :invite_confirm
match 'events/:id/reminder' => 'events#reminder', :as => :event_reminder
match 'events/:id/republish' => 'events#republish', :as => :event_republish
match 'roles/resetMembership' => 'roles#resetMembership', :as => :reset_membership
match 'roles/membership_reminder' => 'roles#membership_reminder', :as => :membership_reminder
root :to => "static_pages#show#home"
Update 2
Ive taken Tims comments on board and cleaned up my routes file however im still seeing the same issue.
My routes now look like
resources :comm_channels
devise_for :users,:path => 'club_users', :controllers => { :registrations => "users/registrations" } do
post '/users', :to => 'users/registrations#create'
end
resources :users
resources :roles,:news ,:invites, :clubs, :events, :albums, :pictures, :static_pages, :sponsors
match "static_pages/:action/:pagetype", :controller => "static_pages"
match 'invites/edit(/:eid/:iid/:code)' => 'invites#edit', :as => :invite_confirm
match 'events/:id/reminder' => 'events#reminder', :as => :event_reminder
match 'events/:id/republish' => 'events#republish', :as => :event_republish
match 'roles/resetMembership' => 'roles#resetMembership', :as => :reset_membership
match 'roles/membership_reminder' => 'roles#membership_reminder', :as => :membership_reminder
root :to => "static_pages#show#home"
Routes output is as follows
users POST /users(.:format) users/registrations#create
new_user_session GET /club_users/sign_in(.:format) devise/sessions#new
user_session POST /club_users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /club_users/sign_out(.:format) devise/sessions#destroy
user_password POST /club_users/password(.:format) devise/passwords#create
new_user_password GET /club_users/password/new(.:format) devise/passwords#new
edit_user_password GET /club_users/password/edit(.:format) devise/passwords#edit
PUT /club_users/password(.:format) devise/passwords#update
cancel_user_registration GET /club_users/cancel(.:format) users/registrations#cancel
user_registration POST /club_users(.:format) users/registrations#create
new_user_registration GET /club_users/sign_up(.:format) users/registrations#new
edit_user_registration GET /club_users/edit(.:format) users/registrations#edit
PUT /club_users(.:format) users/registrations#update
DELETE /club_users(.:format) users/registrations#destroy
GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
I still see the same error in production setup.
Started PUT "/users/21" for 194.XXXX at Sun May 11 08:05:48 -0400 2014
ActionController::RoutingError (No route matches [PUT] "/21"):
actionpack (3.2.2) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
actionpack (3.2.2) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call'
railties (3.2.2) lib/rails/rack/logger.rb:26:in `call_app'
railties (3.2.2) lib/rails/rack/logger.rb:16:in `call'
actionpack (3.2.2) lib/action_dispatch/middleware/request_id.rb:22:in `call'
rack (1.4.5) lib/rack/methodoverride.rb:21:in `call'
rack (1.4.5) lib/rack/runtime.rb:17:in `call'
activesupport (3.2.2) lib/active_support/cache/strategy/local_cache.rb:72:in `call'
rack (1.4.5) lib/rack/lock.rb:15:in `call'
actionpack (3.2.2) lib/action_dispatch/middleware/static.rb:61:in `call'
ive tried different also the simplest variation e.g
devise_for :users,:path => 'club_users'
resources :users
And also the reverse
devise_for :users
resources :users, :path => 'useradmin'
No joy. As I said before rake routes tells me its there
PUT /users/:id(.:format) users#update
but somewhere along the line, PUT "/users/21" gets stripped down to "/21".
Any ideas?
I'm not certain why just that particular route is giving you trouble and only in production, but I think there are some general issues with your routes which if you fix, will probably resolve the problem with that particular route.
Firstly, you have:
devise_for :users, :controllers => { :registrations => "users/registrations" } do
post '/users', :to => 'users/registrations#create'
end
devise_for :users
As you can see from your routes, this repetition of devise_for has resulted in most of your routes being duplicates except for the registration routes for which there are two copies of each route; half of them go to your overridden registrations controller (because of the first devise_for) and half of them go to devise's registrations controller (because of the second devise_for. You should only have one devise_for. Which one you keep depends on which registration controller you want to be used by people who are registering. Assuming you want them to use your overridden version, you should remove the second devise_for. Also, in the first devise_for, I think you can remove the post line as that is the default that you would get anyway.
Once you've done this, you'll have one set of devise routes as well as your other user routes (from resources :users). However, you still have a problem; you still have:
user_registration POST /users(.:format) users/registrations#create
from the devise_for, and:
POST /users(.:format) users#create
because of the resources :users. The same http method and path is mapped to different controllers, which isn't going to work. I suggest you give your users controller a different path to keep a clean separation between the work of registering and login etc. (devise) and your user management controller. Instead of:
resources :users,:roles,:news ,:invites, :clubs, :events, :albums, :pictures, :static_pages, :sponsors
try this:
resources :users, :path => 'useradmin'
resources :roles, :news, :invites, :clubs, :events, :albums, :pictures, :static_pages, :sponsors
or whatever appropriate pathname you want instead of useradmin. This will only change the path; it'll keep the route helpers and expected controller name the same, so you should then have:
new_user GET /useradmin/new(.:format) users#new
edit_user GET /useradmin/:id/edit(.:format) users#edit
user GET /useradmin/:id(.:format) users#show
PUT /useradmin/:id(.:format) users#update
DELETE /useradmin/:id(.:format) users#destroy
Or you can do the opposite; keep your user controller at /users and map the devise controllers to another path using :path => 'whatever-you-want' as a parameter to devise_for.
Once you have a clean division like this, hopefully your error will disappear!
Update
I see there's still some overlap in paths (the initial users POST /users(.:format) users/registrations#create in your rake routes output, though this is POST rather than PUT, so doesn't seem like it should be a problem for the PUT (unless you're using the associated users_path helper in a different context). Instead, it would conflict with the later mapping to POST /users(.:format) users#create. This overlap is due to the post '/users', :to => 'users/registrations#create' in your devise_for. However, is there a reason you have this extra mapping? It's equivalent to the user_registration POST /club_users(.:format) users/registrations#create, just /users instead of /club_users. Could you remove it so there's no path overlap? I'm concerned it's having an effect, though I'm guessing a bit without controller/view code.
By the way, I also use webrick in dev. and passenger in prod., and Rails 3.2.17, devise etc., though I'm using Ruby 1.9.3. I don't see any obvious reason why they should be the cause of your problem in themselves. It's more likely to be the routing setup.
Related
Why devise_token_auth break vanilla devise routes?
I am using devise and devise_token_auth in my Rails5 app. Devise omniauth ( facebook/google ) for web and devise_token_auth for mobile app. i defined routes with: scope module: 'api' do namespace :v1 do mount_devise_token_auth_for 'User', at: 'auth' end end devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }, as: 'auth' resources :users and get some routes =========================TOKEN AUTH======================================= new_v1_user_session GET /v1/auth/sign_in(.:format) devise_token_auth/sessions#new v1_user_session POST /v1/auth/sign_in(.:format) devise_token_auth/sessions#create destroy_v1_user_session DELETE /v1/auth/sign_out(.:format) devise_token_auth/sessions#destroy new_v1_user_password GET /v1/auth/password/new(.:format) devise_token_auth/passwords#new edit_v1_user_password GET /v1/auth/password/edit(.:format) devise_token_auth/passwords#edit v1_user_password PATCH /v1/auth/password(.:format) devise_token_auth/passwords#update PUT /v1/auth/password(.:format) devise_token_auth/passwords#update POST /v1/auth/password(.:format) devise_token_auth/passwords#create cancel_v1_user_registration GET /v1/auth/cancel(.:format) devise_token_auth/registrations#cancel new_v1_user_registration GET /v1/auth/sign_up(.:format) devise_token_auth/registrations#new edit_v1_user_registration GET /v1/auth/edit(.:format) devise_token_auth/registrations#edit v1_user_registration PATCH /v1/auth(.:format) devise_token_auth/registrations#update PUT /v1/auth(.:format) devise_token_auth/registrations#update DELETE /v1/auth(.:format) devise_token_auth/registrations#destroy POST /v1/auth(.:format) devise_token_auth/registrations#create new_v1_user_confirmation GET /v1/auth/confirmation/new(.:format) devise_token_auth/confirmations#new v1_user_confirmation GET /v1/auth/confirmation(.:format) devise_token_auth/confirmations#show POST /v1/auth/confirmation(.:format) devise_token_auth/confirmations#create v1_auth_validate_token GET /v1/auth/validate_token(.:format) devise_token_auth/token_validations#validate_token v1_auth_failure GET /v1/auth/failure(.:format) devise_token_auth/omniauth_callbacks#omniauth_failure GET /v1/auth/:provider/callback(.:format) devise_token_auth/omniauth_callbacks#omniauth_success GET|POST /omniauth/:provider/callback(.:format) devise_token_auth/omniauth_callbacks#redirect_callbacks omniauth_failure GET|POST /omniauth/failure(.:format) devise_token_auth/omniauth_callbacks#omniauth_failure GET /v1/auth/:provider(.:format) redirect(301) ======================WEB========================================== new_auth_user_session GET /users/sign_in(.:format) devise/sessions#new auth_user_session POST /users/sign_in(.:format) devise/sessions#create destroy_auth_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy new_auth_user_password GET /users/password/new(.:format) devise/passwords#new edit_auth_user_password GET /users/password/edit(.:format) devise/passwords#edit auth_user_password PATCH /users/password(.:format) devise/passwords#update PUT /users/password(.:format) devise/passwords#update POST /users/password(.:format) devise/passwords#create cancel_auth_user_registration GET /users/cancel(.:format) devise/registrations#cancel new_auth_user_registration GET /users/sign_up(.:format) devise/registrations#new edit_auth_user_registration GET /users/edit(.:format) devise/registrations#edit auth_user_registration PATCH /users(.:format) devise/registrations#update PUT /users(.:format) devise/registrations#update DELETE /users(.:format) devise/registrations#destroy POST /users(.:format) devise/registrations#create new_auth_user_confirmation GET /users/confirmation/new(.:format) devise/confirmations#new auth_user_confirmation GET /users/confirmation(.:format) devise/confirmations#show POST /users/confirmation(.:format) devise/confirmations#create auth_user_google_oauth2_omniauth_authorize GET|POST /omniauth/google_oauth2(.:format) callbacks#passthru auth_user_google_oauth2_omniauth_callback GET|POST /omniauth/google_oauth2/callback(.:format) callbacks#google_oauth2 auth_user_facebook_omniauth_authorize GET|POST /omniauth/facebook(.:format) callbacks#passthru auth_user_facebook_omniauth_callback GET|POST /omniauth/facebook/callback(.:format) but routes for web must be like auth_user_google_oauth2_omniauth_authorize GET|POST /users/auth/google_oauth2(.:format) callbacks#passthru auth_user_google_oauth2_omniauth_callback GET|POST /users/auth/google_oauth2/callback(.:format) callbacks#google_oauth2 auth_user_facebook_omniauth_authorize GET|POST /users/auth/facebook(.:format) callbacks#passthru auth_user_facebook_omniauth_callback GET|POST /users/auth/facebook/callback(.:format) When i comment devise_token_auth initializer all web routes are fine, but when i turn on initializer - it`t broken. Initializers for devise and token_auth are default. how i can fix it?
How to reroute standard rest actions to devise controller?
I have been building devise into a small Rails app. It's a pretty standard setup but one wrinkle is that the default authentication rules need to be changed for this project. Non-idempotent registration actions must all be restricted to only authenticated users. To do this, I've written a custom registrations controller and linked it up in the routing. All the custom controller really has to do is alter the filtering requirements. Based on the Rails controller filtering documentation, I got this working with a minimum of effort. But by itself that only applies to devise-specific actions like /users/sign_up or /users/edit. I would also like to wire in the standard Rails actions (/users/new, /users/1/edit, etc) to the custom controller. I can get the action to instantiate the controller -- leading the horse to water so to speak -- but when the action is new instead of sign_up, it crashes out during the filtering. The problem appears to be that resource_name yields nil when the action is 'new', but is fine when it's 'sign_up'. I don't understand why devise cares or where the distinction is represented in code. I've looked at other questions like Update the User controller of devise and Override devise registrations controller and Custom Devise controller but they don't get into this issue. The specific error I am getting is NoMethodError in RegistrationsController#new undefined method `name' for nil:NilClass and the top of the trace is devise (2.1.2) app/controllers/devise_controller.rb:22:in resource_name' app/controllers/registrations_controller.rb:104:in authenticate_scope!' It is apparently happening the first time devise_mapping is referenced. But as per the above stackoverflow question I have also explicitly provided helpers for devise_mapping, and they don't even get called. Can anyone explain or help me figure out where to look further? from routes.rb: Fs::Application.routes.draw do devise_for :users, :controllers => { :registrations => 'registrations' } resources :users, :except => [:index, :show], :controller => 'registrations' resources :users, :only => [:index, :show] [...] rake routes reports: new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy user_password POST /users/password(.:format) devise/passwords#create new_user_password GET /users/password/new(.:format) devise/passwords#new edit_user_password GET /users/password/edit(.:format) devise/passwords#edit PUT /users/password(.:format) devise/passwords#update cancel_user_registration GET /users/cancel(.:format) registrations#cancel user_registration POST /users(.:format) registrations#create new_user_registration GET /users/sign_up(.:format) registrations#new edit_user_registration GET /users/edit(.:format) registrations#edit PUT /users(.:format) registrations#update DELETE /users(.:format) registrations#destroy users POST /users(.:format) registrations#create new_user GET /users/new(.:format) registrations#new edit_user GET /users/:id/edit(.:format) registrations#edit user PUT /users/:id(.:format) registrations#update DELETE /users/:id(.:format) registrations#destroy GET /users(.:format) users#index GET /users/:id(.:format) users#show my registrations_controller.rb: class RegistrationsController < Devise::RegistrationsController prepend_before_filter :authenticate_scope!, :except => [:index, :show] skip_filter :require_no_authentication end my users_helper.rb: module UsersHelper # used by devise def resource_name :user end def resource #resource ||= User.new end def devise_mapping #devise_mapping ||= Devise.mappings[:user] end end using: Rails 3.2.6 Ruby 1.9.3 devise 2.1.2 Update: pasted in the correct trace output.
So one solution appears to be to add devise_scope :user do get '/users/new' => 'registrations#new' end into routes.rb. This may not be the best answer but it works.
Custom Rails 3 routes
Suppose I have an events controller. If I request /events by GET it will respond with index action in news controller, this view will display future events. I want to add a new action called past, it is like index, which return an array of Events but with another query. I have added to routes.rb this chunk: resources :events do collection do get :past end end and I this chuck to events_controller: def history #events => Event.past render :template => 'index' end But when I request http://127.0.0.1:3000/events/past in browser it does not work, in log are thrown these lines: Started GET "/events/past" for 127.0.0.1 at 2012-04-02 19:32:01 -0500 Processing by EventsController#show as HTML Parameters: {"id"=>"past"} And finally here you have rake routes output: events GET /events(.:format) {:action=>"index", :controller=>"events"} event GET /events/:id(.:format) {:action=>"show", :controller=>"events"} past_events GET /events/past(.:format) {:action=>"past", :controller=>"events"} contact_us_event POST /events/:id/contact_us(.:format) {:action=>"contact_us", :controller=>"events"} GET /events(.:format) {:action=>"index", :controller=>"events"} POST /events(.:format) {:action=>"create", :controller=>"events"} new_event GET /events/new(.:format) {:action=>"new", :controller=>"events"} edit_event GET /events/:id/edit(.:format) {:action=>"edit", :controller=>"events"} GET /events/:id(.:format) {:action=>"show", :controller=>"events"} PUT /events/:id(.:format) {:action=>"update", :controller=>"events"} DELETE /events/:id(.:format) {:action=>"destroy", :controller=>"events"} Other test was check routes using Rails console: $ script/rails c 1.9.2-p318 :001 > rs = ActionController::Routing::Routes 1.9.2-p318 :002 > rs.recognize_path "/events/past", :method => :get => {:action=>"show", :controller=>"events", :id=>"past"} What's wrong?
The problem was on routes precedence, here you have a routes.rb chunk that works: resources :events, :only => [:index, :show] do get 'past', :on => :collection post 'contact_us', :on => :member end
Try: resources :events do get :past, :to => "events#past" end I don't think you need the collection context. (And you might not need the :to part) Update Another way to do it is to put the event call above the resource. Assuming you don't need the collection with it. get 'events/past', :to => "events#past" resources :events Should provide you with the correct routes. For reference: Rails 3 routes: How to avoid conflict with 'show' action?
How do I remove the Devise route to sign up?
I'm using Devise in a Rails 3 app, but in this case, a user must be created by an existing user, who determines what permissions he/she will have. Because of this, I want: To remove the route for users to sign up. To still allow users to edit their profiles (change email address and password) after they have signed up How can I do this? Currently, I'm effectively removing this route by placing the following before devise_for :users: match 'users/sign_up' => redirect('/404.html') That works, but I imagine there's a better way, right? Update As Benoit Garret said, the best solution in my case is to skip creating the registrations routes en masse and just create the ones I actually want. To do that, I first ran rake routes, then used the output to re-create the ones I wanted. The end result was this: devise_for :users, :skip => [:registrations] as :user do get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration' put 'users' => 'devise/registrations#update', :as => 'user_registration' end Note that: I still have :registerable in my User model devise/registrations handles updating email and password Updating other user attributes - permissions, etc - is handled by a different controller Actual answer: Remove the route for the default Devise paths; i.e.: devise_for :users, path_names: { sign_up: '' }
you can do this in your model # typical devise setup in User.rb devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable change it to: devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable notice that the symbol :registerable was removed That's it, nothing else is required. All routes and links to registration page are magically removed too.
I tried to do this as well, but a thread on the devise google group dissuaded me from searching for a really clean solution. I'll quote José Valim (the Devise maintainer) : There isn't a straight-forward option. You can either provide a patch or use :skip => :registerable and add only the routes you want. The original question was : Is there any good way to remove a specific route (the delete route) from Rails?
I had similar issue tried to remove devise_invitable paths for create and new : before: devise_for :users rake routes accept_user_invitation GET /users/invitation/accept(.:format) devise/invitations#edit user_invitation POST /users/invitation(.:format) devise/invitations#create new_user_invitation GET /users/invitation/new(.:format) devise/invitations#new PUT /users/invitation(.:format) devise/invitations#update after devise_for :users , :skip => 'invitation' devise_scope :user do get "/users/invitation/accept", :to => "devise/invitations#edit", :as => 'accept_user_invitation' put "/users/invitation", :to => "devise/invitations#update", :as => nil end rake routes accept_user_invitation GET /users/invitation/accept(.:format) devise/invitations#edit PUT /users/invitation(.:format) devise/invitations#update note 1 devise scope https://github.com/plataformatec/devise#configuring-routes note 2 I'm applying it on devise_invitable but it will work with any devise *able feature Important note: see that devise_scope is on user not users ? that's correct, watch out for this ! It can cause lot of pain giving you this problem: Started GET "/users/invitation/accept?invitation_token=xxxxxxx" for 127.0.0.1 Processing by Devise::InvitationsController#edit as HTML Parameters: {"invitation_token"=>"6Fy5CgFHtjWfjsCyr3hG"} [Devise] Could not find devise mapping for path "/users/invitation/accept? invitation_token=6Fy5CgFHtjWfjsCyr3hG". This may happen for two reasons: 1) You forgot to wrap your route inside the scope block. For example: devise_scope :user do match "/some/route" => "some_devise_controller" end 2) You are testing a Devise controller bypassing the router. If so, you can explicitly tell Devise which mapping to use: #request.env["devise.mapping"] = Devise.mappings[:user]
I found another post similar to this one and wanted to share an answer #chrisnicola gave. In the post they were attempting to only block user signup's during production. You could also modify the registrations controller. You can use something like this: In "app/controllers/registrations_controller.rb" class RegistrationsController < Devise::RegistrationsController def new flash[:info] = 'Registrations are not open.' redirect_to root_path end def create flash[:info] = 'Registrations are not open.' redirect_to root_path end end This will override devise's controller and use the above methods instead. They added flash messages incase that someone somehow made it to the sign_up page. You should also be able to change the redirect to any path you like. Also in "config/routes.rb" you can add this: devise_for :users, :controllers => { :registrations => "registrations" } Leaving it like this will allow you to use the standard devise edit your profile. If you wish you can still override the edit profile option by including def update end in the "app/controllers/registrations_controller.rb"
This is an old question - but I recently had solve the same issue and came up with a solution which is far more elegant than: devise_for :users, :skip => [:registrations] as :user do get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration' put 'users' => 'devise/registrations#update', :as => 'user_registration' end And it gives the default names for the named routes (like cancel_user_registration) without being excessively verbose. devise_for :users, skip: [:registrations] # Recreates the Devise registrations routes # They act on a singular user (the signed in user) # Add the actions you want in 'only:' resource :users, only: [:edit, :update, :destroy], controller: 'devise/registrations', as: :user_registration do get 'cancel' end rake routes output with the default devise modules: Prefix Verb URI Pattern Controller#Action new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy user_password POST /users/password(.:format) devise/passwords#create new_user_password GET /users/password/new(.:format) devise/passwords#new edit_user_password GET /users/password/edit(.:format) devise/passwords#edit PATCH /users/password(.:format) devise/passwords#update PUT /users/password(.:format) devise/passwords#update cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel edit_user_registration GET /users/edit(.:format) devise/registrations#edit user_registration PATCH /users(.:format) devise/registrations#update PUT /users(.:format) devise/registrations#update DELETE /users(.:format) devise/registrations#destroy
You can override the "devise_scope" by placing it before the "devise_for". devise_scope :user do get "/users/sign_up", :to => "sites#index" end devise_for :users Not sure if this is the best way but its my solution currently, as it just redirects back to the sign in page.
I liked #max's answer, but when trying to use it I ran into an error due to devise_mapping being nil. I modified his solution slightly to one that seems to address the issue. It required wrapping the call to resource inside devise_scope. devise_for :users, skip: [:registrations] devise_scope :user do resource :users, only: [:edit, :update, :destroy], controller: 'devise/registrations', as: :user_registration do get 'cancel' end end Note that devise_scope expects the singular :user whereas resource expects the plural :users.
Do This in routes.rb devise_for :users, :controllers => {:registrations => "registrations"}, :skip => [:registrations] as :user do get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration' put 'users' => 'devise/registrations#update', :as => 'user_registration' end devise_scope :user do get "/sign_in", :to => "devise/sessions#new" get "/sign_up", :to => "devise/registrations#new" end you will get an error now while you come to sign in page, to fix it. Do this change in: app/views/devise/shared/_links.erb <% if request.path != "/sign_in" %> <%- if devise_mapping.registerable? && controller_name != 'registrations' %> <%= link_to "Sign up", new_registration_path(resource_name) %><br /> <% end -%> <% end %>
I've found this to work well without messing with routes or adding application controller methods. My approach is to override the devise method. Add this to app/controllers/devise/registrations_controller.rb I've omitted the other methods for brevity. class Devise::RegistrationsController < DeviseController ... # GET /resource/sign_up def new redirect_to root_path end .... end Also to remove illusion that this path is still reachable from other views you might also want to remove this code from app/views/devise/shared/_links.erb <%- if devise_mapping.registerable? && controller_name != 'registrations' %> <%= link_to "Sign up", new_registration_path(resource_name) %><br /> <% end -%>
For others in my case. With devise (3.5.2). I successfully removed the routes to signup, but kept the ones to edit the profile, with the following code. #routes.rb devise_for :users, skip: [:registrations] as :user do get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration' put '/users(.:format)' => 'devise/registrations#update', as: 'user_registration' patch '/users(.:format)' => 'devise/registrations#update' end
Here's the slightly different route I went. It makes it so you don't have to override the devise/shared/_links.html.erb view. In app/models/user.rb: devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable In config/routes.rb: devise_for :users devise_scope :user do put 'users' => 'devise/registrations#update', as: 'user_registration' get 'users/edit' => 'devise/registrations#edit', as: 'edit_user_registration' delete 'users' => 'devise/registrations#destroy', as: 'registration' end Before: $ rake routes | grep devise new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy user_password POST /users/password(.:format) devise/passwords#create new_user_password GET /users/password/new(.:format) devise/passwords#new edit_user_password GET /users/password/edit(.:format) devise/passwords#edit PATCH /users/password(.:format) devise/passwords#update PUT /users/password(.:format) devise/passwords#update cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel user_registration POST /users(.:format) devise/registrations#create new_user_registration GET /users/sign_up(.:format) devise/registrations#new edit_user_registration GET /users/edit(.:format) devise/registrations#edit PATCH /users(.:format) devise/registrations#update PUT /users(.:format) devise/registrations#update DELETE /users(.:format) devise/registrations#destroy After: $ rake routes | grep devise new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy user_password POST /users/password(.:format) devise/passwords#create new_user_password GET /users/password/new(.:format) devise/passwords#new edit_user_password GET /users/password/edit(.:format) devise/passwords#edit PATCH /users/password(.:format) devise/passwords#update PUT /users/password(.:format) devise/passwords#update user_registration PUT /users(.:format) devise/registrations#update edit_user_registration GET /users/edit(.:format) devise/registrations#edit registration DELETE /users(.:format) devise/registrations#destroy
Instead of searching for a hard solution. I used the below approaches. Delete the sign_up form from page (path devise/registrations/new.html.erb) and replace it with custom info. Redirect the incoming traffic to some other page. Like below in routes.rb get "/users/sign_up", to: redirect('/') post "/users/sign_up", to: redirect('/') Make sure to write it before devise_for :users
I had the same issue and I found it a bit bad practise to redirect users from the registration page. So my solution is basically is not using :registrable at all. What I did was to create a similar page like edit user details which looked like: <%= form_tag(update_user_update_path, method: :post) do %> <br> <%= label_tag(:currPassword, 'Current password:') %> <%= password_field_tag(:currPassword) %> <br> <%= label_tag(:newPassword, 'New password:') %> <%= password_field_tag(:newPassword) %> <br> <%= label_tag(:newPasswordConfirm, 'Confirm new password:') %> <%= password_field_tag(:newPasswordConfirm) %> <br> <%= submit_tag('Update') %> <% end %> So this form submits into a new post end point that updates the password, which looks like: def update currPass = params['currPassword'] newPass1 = params['newPassword'] newPass2 = params['newPasswordConfirm'] currentUserParams = Hash.new() currentUserParams[:current_password] = currPass currentUserParams[:password] = newPass1 currentUserParams[:password_confirmation] = newPass2 #result = current_user.update_with_password(currentUserParams) end Later on you can use the #result in your view to tell the user whether the password is updated or not.
By changing the routes there are a whole bunch of other problems that come with that. The easiest method I have found is to do the following. ApplicationController < ActionController::Base before_action :dont_allow_user_self_registration private def dont_allow_user_self_registration if ['devise/registrations','devise_invitable/registrations'].include?(params[:controller]) && ['new','create'].include?(params[:action]) redirect_to root_path end end end
You could modify the devise gem itself. First, run this command to find the installed location of using: gem which devise Let's suppose the path is: /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise Then go to /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/rails and edit routes.rb in that directory. There is a method called def devise_registration(mapping, controllers) which you can modify to get rid of the new action. You can also completely remove the mappings for devise_registration
Rails RoutingError: No route matches {:controller=>"sessions", :action=>"destroy"}
Yet when run rake:routes it appears to be there: users GET /users(.:format) {:action=>"index", :controller=>"users"} POST /users(.:format) {:action=>"create", :controller=>"users"} new_user GET /users/new(.:format) {:action=>"new", :controller=>"users"} edit_user GET /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"} user GET /users/:id(.:format) {:action=>"show", :controller=>"users"} PUT /users/:id(.:format) {:action=>"update", :controller=>"users"} DELETE /users/:id(.:format) {:action=>"destroy", :controller=>"users"} sessions POST /sessions(.:format) {:action=>"create", :controller=>"sessions"} new_session GET /sessions/new(.:format) {:action=>"new", :controller=>"sessions"} session DELETE /sessions/:id(.:format) {:action=>"destroy", :controller=>"sessions"} signup /signup(.:format) {:controller=>"users", :action=>"new"} contact /contact(.:format) {:controller=>"pages", :action=>"contact"} about /about(.:format) {:controller=>"pages", :action=>"about"} help /help(.:format) {:controller=>"pages", :action=>"help"} root /(.:format) {:controller=>"pages", :action=>"home"} Here are the routes from routes.rb: resources :users resources :sessions, :only => [:new, :create, :destroy] match '/signup', to: 'users#new' match '/contact', to: 'pages#contact' match '/about', to: 'pages#about' match '/help', to: 'pages#help'
It's possible that you are not passing the :id param in your route, which is why the route is not matched, since :id is required: session DELETE /sessions/:id(.:format) {:action=>"destroy", :controller=>"sessions"} Note: The parentheses around the :format param mean that it is optional.
I got the same error as well.But the reason is the little mistake that in the view page I write <%= form_for(:session,url:session_path) do |f| %> which I less the last 's' of 'sessions'.
This looks like an error I was running into when running through http://ruby.railstutorial.org/, and it turned out that I had left a few things out of routes.rb. The addition of the resource route is accompanied by the following two additional routes: match '/signin', :to => 'sessions#new' match '/signout', :to => 'sessions#destroy' It's hard to see because the first route in that group is already there, so I had just glossed over the group (several times) as already being there.
resources controller adds map to method {:action=>"method", :controller=>"controller"} when in your case the rails seemed to ask for explicitly the map as {:controller=>“controller”, :action=>“method”} The :controller is before :action This also answered Noach's question why match '/signout', :to => 'sessions#destroy' has to exist, if you rake:routes you will see it added {:controller=>“sessions”, :action=>“destroy”} while there is already a {:action=>“destroy”, :controller=>“sessions”} added by resources sessions