Rails + Devise - Is there a way to BAN a user so they can't login or reset their password?
I have a lot of users thanks to devise and I want to ban a few p开发者_运维知识库roblem makers. Does Devise have this support built in?
Thanks
From the devise doku for authenticatable.rb:
Before authenticating a user and in each request, Devise checks if your model is active by calling model.active_for_authentication?. This method is overwriten by other devise modules. For instance, :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.
You overwrite this method yourself, but if you do, don't forget to call super:
def active_for_authentication?
super && special_condition_is_valid?
end
So, when you have a flag blocked
in the user database, the method in the user model looks something like this:
def active_for_authentication?
super && !self.blocked
end
I just implemented this in my project myself. What I did was similar to Kleber above, I defined this in my app/controllers/sessions_controller.rb (overriding Devise)...
class SessionsController < Devise::SessionsController
protected
def after_sign_in_path_for(resource)
if resource.is_a?(User) && resource.banned?
sign_out resource
flash[:error] = "This account has been suspended for violation of...."
root_path
else
super
end
end
end
And then I added a boolean column to Users called 'banned,' so the moderators check the checkbox when editing the user in the backend, and the boolean will return true.
But there was one flaw...if a user was already logged in and then banned, they still had access to doing stuff on the site (comments, etc) at least until their session expired or they logged out. So I did this in the app/controllers/application_controller.rb...
class ApplicationController < ActionController::Base
before_filter :banned?
def banned?
if current_user.present? && current_user.banned?
sign_out current_user
flash[:error] = "This account has been suspended...."
root_path
end
end
end
That'll automatically log them out if a ban is detected. Anyway, not sure this whole thing is the "best" way to factor the whole thing as I'm newer to Rails, but the whole thing works for me and hope it will at least give you a good start.
Customize user account status validation when logging in
Sometimes you want to add custom validation to the user before logging them in. In this case I needed to implement an account_active boolean (true or false) check. So if it's true it will allow the user to login and create a session, if false it will display the "account not active" error.
Overwrite the active_for_authentication? method in your model (User) and add your validation logic. You want to return super && (true or false)
def active_for_authentication?
# Uncomment the below debug statement to view the properties of the returned self model values.
# logger.debug self.to_yaml
super && account_active?
end
In this case it checks the boolean value to account_active and it return it's value to the sign in method that called it.
The original active_for_authentication? method can be found in devise/lib/devise/models/authenticatable.rb.
Note: active_for_authentication? is called by Devise after authenticating user and in each request that follows. This means whatever code you add to the override of active_for_authentication? will be run for every request during the user's session.
Note: active_for_authentication? is not being called for each request when using database_authenticatable. It only gets called on login. Not sure if this is intended behavior.
Customize error message
If the method 'active_for_authentication?' returns false, method 'inactive_message' is invoked, user will receive notification for being inactive. We need to customize the message as well:
def inactive_message
account_active? ? super : :account_inactive
end
Now this will refer the custom message for 'account_inactive' and not 'inactive', which we need to define in devise translation file.
devise:
failure:
inactive: 'Your account was not activated yet.'
account_inactive: 'Your account is not active.'
registrations:
signed_up_but_account_inactive: "Thanks for signing up. We'll let you know when your account is active"
You could add a field called "banned" to your Users table.
and then, on your Controller, you can have something like this:
class UsersController < ApplicationController
before_filter :deny_banned
protected
def deny_banned
if current_user.banned?
redirect_to root_path, :notice => "You are banned from this site."
end
end
end
This is not complete but I hope it helps you somehow.
精彩评论