ruby on rails - How can I allow Devise users to log in when they're outside my default scope? -


i have rails 4 app uses devise 3.4 authentication, i've customized ability ban users (using simple boolean column users.banned, default false). user model has default_scope returns non-banned users.

here's problem - still want banned users able log in, though can't after logging in. (they see page saying "you've been banned"). seems default_scope tripping devise. when log in or call e.g. authenticate_user!, devise tries find current user using 1 of basic activerecord methods find or find_by, can't because lie outside default scope. devise concludes user doesn't exist, , login fails.

how can make devise ignore default scope?

after long time digging around in devise , warden source code, found solution.

short answer:

add user class:

def self.serialize_from_session(key, salt)   record = to_adapter.klass.unscoped.find(key[0])   record if record && record.authenticatable_salt == salt end 

(note i've tested activerecord; if you're using different orm adapter need change first line of method... i'm not sure if other orm adapters have concept of "default so

long answer:

serialize_from_session mixed user class -devise::models::authenticatable::classmethods. honestly, i'm not sure it's supposed do, it's public method , documented (very sparsely) in devise api, don't think there's chance of being removed devise without warning.

here's original source code of devise 3.4.1:

def serialize_from_session(key, salt)   record = to_adapter.get(key)   record if record && record.authenticatable_salt == salt end 

the problem lies to_adapter.get(key). to_adapter returns instance of ormadapter::activerecord wrapped around user class, , to_adapter.get same calling user.find. (devise uses orm_adapter gem keep flexible; above method work without modification whether you're using activerecord, mongoid or other ormadapter-compatible orm.)

but, of course, user.find searches within default_scope, why can't find banned users. calling to_adapter.klass returns user class directly, , can call unscoped.find search all users , make banned ones visible devise. working line is:

record = to_adapter.klass.unscoped.find(key[0]) 

note i'm passing key[0] instead of key, because key array (in case 1 element) , passing array find return array, isn't want.

also note calling klass within real devise source code bad idea, means lose advantages of ormadapter. within own app, know certainty orm you're using (something devise doesn't know), it's safe specific.


Popular posts from this blog

c# - ODP.NET Oracle.ManagedDataAccess causes ORA-12537 network session end of file -

matlab - Compression and Decompression of ECG Signal using HUFFMAN ALGORITHM -

utf 8 - split utf-8 string into bytes in python -