[Devise] Banowanie usera

Wiem, że kilka osób wykorzystuje devise … może podzielicie się pomysłem na “ręczne” blokowanie kont.

Blokowanie automatyczne działa poprawnie, działa również odblokowanie (:email, :time). Chciałbym jednak mieć możliwość zablokowania konta w taki sposób aby użytkownik nie mógł go samodzielne odblokować. Mam taką zasadę, że nie kasuję kont użytkowników a jedynie je blokuję. W przypadku serwisu WWW jest to o tyle istotne, że we wszystkich “dokumentach” pozostaje ich autor.

Oczywiście mogę zastosować config.unlock_strategy = :both ale wówczas zapominacze haseł zamęczą admina telefonami o odblokowanie konta więc to też nie jest dobre rozwiązanie.

Jedyne rozwiązanie jakie znalazłem to http://stackoverflow.com/questions/3894919/what-is-the-best-way-to-ban-block-users-with-devise-for-rails - rozumiem, że tutaj trzeba będzie dodać dodatkowe pole do tabeli users i metodę User#banned?.

Jak oceniacie tą propozycję, macie może jakieś inne rozwiązanie?

To jest całkiem niezłe rozwiązanie. Według mnie bez dodatkowego pola się nie obejdzie.

Zdaje się że devise sprawdza metodę active? w modelu User. Można by tam zrobić “return false if banned?” i to już chyba wystarczy by użytkownik nie mógł się zalogować (tak z głowy). Oczywiście wymaga to dodatkowe pola na bazie.

Jeżeli model ma być :confirmable to odradzam takie podejście, ze względu na to, że active? nadpisywana jest wtedy przez moduł Devise::Models::Confirmable

U mnie to jest tak. Fakt że najpierw loguje a potem wylogowywuje ale jest mniej nadpisywania devisa,

[code]protected

def after_sign_in_path_for(resource)             
  if resource.is_a?(User) && resource.blocked
    sign_out resource
    flash.sweep
    flash[:alert] = "Użytkownik zablokowany"
    root_path
  else
   super
  end
end[/code]

Drobny szczegół: w ruby jest konwencja, że nazwy funkcji zwracających wartość logiczną kończymy pytajnikiem.

Rozumiem ale blocked to jest atrybut typu boolean, więc nie wiem czy jest sens odpalać metodę blocked?
Gdyby blocked było metodą a nie atrybutem to tak.

Nadpisywana czy doinkludowana innym modułem? Jeśli inkludowana to można użyć “super”:

[code]class User

devise_costam_costam # załóżmy że dorzuca moduł

module Bannable
def active?
return false if banned?
super
end
end

include Bannable
end[/code]

Tak. Myślę, że to ‘super’:wink: pomysł. Choć zdaje się, że w tym przypadku wystarczy po prostu nadpisac metodę active? w modelu User.

[code]class User

devise_costam_costam # załóżmy że dorzuca moduł

def active?
return false if banned?
super
end

end[/code]

Metoda after_sign_in_path_for(resource) wywoływana jest tylko w przypadku bezpośredniego requesta typu /users/sign_in
Jeżeli niezalogowany (i zbanowany) user wykona requesta na jakiś inny zasób w stylu /admin/users, wtedy zostanie przekierowany na stronę logowania i po zalogowaniu znajdzie się tam gdzie chciał.
Oto wyciąg ze źródeł devise’a:

def sign_in_and_redirect(resource_or_scope, resource=nil) scope = Devise::Mapping.find_scope!(resource_or_scope) resource ||= resource_or_scope sign_in(scope, resource) unless warden.user(scope) == resource redirect_to stored_location_for(scope) || after_sign_in_path_for(resource) end
Na moje to problem można by rozwiązać jakoś tak:

def sign_in_and_redirect(resource_or_scope, resource=nil) if resource.is_a?(User) && resource.banned? sign_out(resource) redirect_to banned_url else super end end

Sprawdziłem, masz rację :slight_smile:

Dziękuję za wszystkie wypowiedzi.
Z tym tematem już sobie poradziłem i idę dalej.
Z jakiegoś powodu nie działa “Remember me”, chce zabronić jednoczesnego logowania z różnych IP itd. Pewnie jeszcze będę wam zawracał głowę :slight_smile: