Problem overriding Devise::RegistrationsController - ruby-on-rails-3

I've read similar articles like Override devise registrations controller , but Devise in my app doesn't override correctly.
I am using Devise 1.4.2 and Rails 3.0.9 on my Mac (OSX 10.6.8).
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
debugger
end
def create
debugger
end
end
# config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
Then I started my local server with --debugger option (ruby-debug19 is installed) and when access to /users/sign_up, debugger doesn't trigger.
rails server --debugger
Started GET "/users/sign_up" for 127.0.0.1 at 2011-07-11 21:21:46 +0900
Processing by Devise::RegistrationsController#new as HTML
Rendered devise/shared/_links.erb (3.8ms)
Rendered devise/registrations/new.html.erb within layouts/application (20.4ms)
Updated: I checked my routings with "rake routes", but the routing for sign_up still remains as below.
user_registration POST /users(.:format) {
:action=>"create", :controller=>"devise/registrations"}
new_user_registration GET /users/sign_up(.:format) {
:action=>"new", :controller=>"devise/registrations"}
I want :controller to point "registrations" (without "devise/") when POST.
What am I missing?

In your routes.rb file,
You can amend your devise routes in the following way:
devise_for :users, :controllers => { :registrations => 'registrations' }

Related

The action 'google_oauth2' could not be found for Users::OmniauthCallbacksController

I'm using 'omniauth-google-oauth2' for sign in with google and follow all instruction here carefully
https://github.com/plataformatec/devise/wiki/OmniAuth%3A-Overview
but i have error above.
my routes
devise_for :users, :controllers => {
:omniauth_callbacks => "users/omniauth_callbacks"
}
devise.rb code
config.omniauth :google_oauth2, "863625299460- 420n6c7lvad91dfvko60uamtvtr6huhf.apps.googleusercontent.com", "dcvA2aZRZi27KCQjWTYP30pw", { access_type: "offline", approval_prompt: "" }
omniauth callback controller code
def google_oauth2
##user = User.find_for_google_oauth2(request.env["omniauth.auth"], current_user)
binding.pry #control not coming here
end
i have error below after callback. see screenshot
https://github.com/zquestz/omniauth-google-oauth2/issues/52
This looks like a route issue. If you do "rake routes | grep auth" what do you see?
I had exactly the same problem you described. Make sure you require the omniauth-google-oauth2 gem in config/initializers/deviser.rb
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
require "omniauth-google-oauth2"
config.omniauth :google_oauth2, ENV["GOOGLE_KEY"], ENV["GOOGLE_SECRET"],
{ access_type: "offline", approval_prompt: "force" }
I've added the entire portion of my devise.rb file to provide context.
It's very late but this answer might be useful for others
If you are using devise for authentication then devise by default generates routes in the route file devise_for :users and your omniouth_callback route should be above the default devise route so that it overwrites default devise route.
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks"}
devise_for :users

Overriding Devise Passwords Controller

I want to disable the
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
if successfully_sent?(resource)
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
else
respond_with(resource)
end
end
so it won't redirect at all after sending the reset password
So, I created a new file under app/controllers/users/ called passwords_controller.rb
which looks like this
class User::PasswordsController < Devise::PasswordsController
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
if successfully_sent?(resource)
flash[:notice] = "sent password"
else
respond_with(resource)
end
end
def new
super
end
def update
super
end
def edit
super
end
end
and changed in my routes to
devise_for :users, :controllers => { :invitations => 'users/invitations', :passwords => 'users/passwords' }
I also have the devise_invite gem..
When I click on a link for forgotten password I get this error
Started GET "/users/password/new" for 127.0.0.1 at 2012-11-16 10:21:07 +0200
ActionController::RoutingError (uninitialized constant Users::PasswordsController):
my rake routes are
user_password POST /users/password(.:format) users/passwords#create
new_user_password GET /users/password/new(.:format) users/passwords#new
edit_user_password GET /users/password/edit(.:format) users/passwords#edit
PUT /users/password(.:format) users/passwords#update
the link in the view is
<%= link_to "Forgot your password?", new_password_path(User) , :class => "control-group", :style => "position: absolute; bottom: 0", :id=>"forgotpass" %>
What am I missing?
The password controller is extended from devise password controller. So, extend the password controller with devise password controler.
class PasswordsController < Devise::PasswordsController
......................
end
Change the routes for password controller with devise
devise_for :users, :controllers => { :passwords => "passwords" }
and the routes will be like this :-
user_password POST /password(.:format) Passwords#create
new_user_password GET /password/new(.:format) Passwords#new
edit_user_password GET /password/edit(.:format) Passwords#edit
PUT /password(.:format) Passwords#update
If you would like to keep a namespace, try:
# routes.rb
devise_for :users, controllers: { passwords: 'users/passwords' }
# users/passwords_controller.rb
class Users::PasswordsController < Devise::PasswordsController
...
end

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.

Unable to delete resource after overriding devise registrations controller

I have followed this devise how to: Redirect to a specific page on successful sign up.
I have created a new RegistrationsController
class RegistrationsController < Devise::RegistrationsController
def after_inactive_sign_up_path_for(resource)
...
end
def destroy
logger.debug 'destroy user'
...
end
end
I have changed routes.rb :
devise_for :users, :controllers => { :registrations => "registrations" } do
get 'users', :to => 'profile#index', :as => :user_root
end
and moved devise/registrations/ views under my new RegistrationsController.
With rake routes I have :
DELETE /users(.:format) {:action=>"destroy", :controller=>"registrations"}
after_inactive_sign_up_path_for is working.
But destroy action doesn't work : when I cancel my account
<%= button_to "Cancel my account", registration_path(resource_name), :confirm => "ok?", :method => :delete %>
I have the following error :
The action 'destroy' could not be found for RegistrationsController
I use Devise 1.4.5 & Rails 3.1
I just ran into the same issue. Moving the destroy method to the non private section of the controller fixed it.

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