4
votes

In my Rails project I have different types of users one of which has the user_status :admin, which has full rights to edit content unlike the rest of the users. For obvious reasons I want to add additional security for these types of users, in particular, completely disable password recovery.

What is the correct way of overriding standard Devise password recovery (:recoverable Devise module) methods so that when a user tries to get a reset password link for a user which is an admin user (user_status == "admin") the system gives back the "standard email not found" message?

This is somewhat like the unanswered question: Restrict Devise password recovery to only certain users

Thank you in advance.

4

4 Answers

3
votes

For any future viewers, here's another way to do it. Vitaly's example did work for me, but I was still getting the "Your password email has been sent." notice (I wanted a separate alert to flash), so I went another route.

Extending the Devise::PasswordsController was the easiest solution for me:

class Devise::Extends::PasswordsController < Devise::PasswordsController

  def create
    if some_condition?
      redirect_to :root
      flash[:alert] = 'You cannot reset your password, buddy.'
    else
      super
    end
  end

Then, in routes.rb:

devise_for :users, controllers: { passwords: 'devise/extends/passwords' }

That will direct your app to the extended controller, then hit the devise controller ("super") if your condition is not met.

9
votes

The method I chose and that worked for me was overriding the send_reset_password_instructions method of the User model by adding the following to models/user.rb:

def send_reset_password_instructions
  return false if self.user_status == 'admin'
  super
end

This makes Devise not do anything in case the email belongs to an admin account.

2
votes

Not tested, but I think you can overwrite the reset_password! in the User model as follows:

def reset_password!(new_password, new_password_confirmation)
  return false if user_status == 'admin'
  super
end

This prevents the password from being reset if the user is an admin.

I don't know if this is the best method to override, there are more devise recoverable methods that are candidate to be overwritten in your User model, ie send_reset_password_instructions. Check the manual for all the interesting methods.

0
votes

Snippet above from Keller Martin works pretty well!

Some minor issues I faced are the following:

  1. If you got uninitialized constant Devise::Extends (NameError) (probably it's just due to old ruby version?) then you can just use nested modules definition.
  2. If you need to allow some action to run for non authenticated user then you can skip the filter.

Below is updated snippet.

module Devise
  module Extends
    class PasswordsController < Devise::PasswordsController

      skip_before_filter :authenticate_user!, :only => [ :edit ]

      def edit
        redirect_to "https://www.google.com/"
      end

    end
  end
end