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