I've found a quite interesting way to overcome this by using a session variable to remember which user has logged out. The idea is that even though the browser's still sending authentication data, we're just ignoring it, because the user chose to log out. Whenever a new login request is sent to the browser, all the authentication data is erased, so the user is able to log back in any time.
class ApplicationController < ActionController::Base
# ...
before_filter :authenticate
protected
def authenticate
authenticate_with_http_basic do |username, password|
@current_user = User.find_by_name_and_crypted_password(username, User.digest(password))
@current_user = nil if @current_user && session[:logged_out] == @current_user.id
!@current_user.nil?
end
end
def authenticate!
return if @current_user
session[:authenticate_uri] = request.request_uri
redirect_to('/login')
end
end
Then, on the events controller I do:
class EventsController < ApplicationController
before_filter :authenticate!, :only => [ :new, :create, :edit, :update ]
#...
end
And finally my session controller looks like this:
class SessionController < ApplicationController
before_filter :authenticate!, :only => [ :create ]
def create
if session[:authenticate_uri]
redirect_to(session[:authenticate_uri])
session[:authenticate_uri] = nil
else
redirect_to(new_event_path)
end
end
def destroy
session[:logged_out] = @current_user.id
redirect_to '/'
end
protected
def authenticate!
authenticate_or_request_with_http_basic("Rankings") do |username, password|
@current_user = User.find_by_name_and_crypted_password(username, User.digest(password))
if @current_user && session[:logged_out] == @current_user.id
@current_user = nil
session[:logged_out] = nil
end
!@current_user.nil?
end
end
end
And don't forget your routes!
map.logout 'login', :controller => 'session', :action => 'create'
map.logout 'logout', :controller => 'session', :action => 'destroy'