require 'clearance/session_status' module Clearance # The base class for {DefaultSignInGuard} and all custom sign in guards. # # Sign in guards provide you with fine-grained control over the process of # signing in a user. Each guard is run in order and can do one of the # following: # # * Fail the sign in process # * Call the next guard in the stack # * Short circuit all remaining guards, declaring sign in successfull. # # Sign In Guards could be used, for instance, to require that a user confirm # their email address before being allowed to sign in. # # # in config/initializers/clearance.rb # Clearance.configure do |config| # config.sign_in_guards = ["ConfirmationGuard"] # end # # # in app/guards/confirmation_guard.rb # class ConfirmationGuard < Clearance::SignInGuard # def call # if signed_in? && current_user.email_confirmed? # next_guard # else # failure("You must confirm your email address.") # end # end # end # # Calling `success` or `failure` in any guard short circuits all of the # remaining guards in the stack. In most cases, you will want to either call # `failure` or `next_guard`. The {DefaultSignInGuard} will always be the final # guard called and will handle calling `success` if appropriate. # # The stack is designed such that calling `call` will eventually return # {SuccessStatus} or {FailureStatus}, thus halting the chain. class SignInGuard # Creates an instance of a sign in guard. # # This is called by {Session} automatically using the array of guards # configured in {Configuration#sign_in_guards} and the {DefaultSignInGuard}. # There is no reason for users of Clearance to concern themselves with the # initialization of each guard or the stack as a whole. # # @param [Session] session The current clearance session # @param [[SignInGuard]] stack The sign in guards that come after this # guard in the stack def initialize(session, stack = []) @session = session @stack = stack end # Indicates the entire sign in operation is successful and that no further # guards should be run. # # In most cases your guards will want to delegate this responsibility to the # {DefaultSignInGuard}, allowing the entire stack to execute. In that case, # your custom guard would likely want to call `next_guard` instead. # # @return [SuccessStatus] def success SuccessStatus.new end # Indicates this guard failed, and the entire sign in process should fail as # a result. # # @param [String] message The reason the guard failed. # @return [FailureStatus] def failure(message) FailureStatus.new(message) end # Passes off responsibility for determining success or failure to the next # guard in the stack. # # @return [SuccessStatus, FailureStatus] def next_guard stack.call end private attr_reader :stack, :session # True if there is a currently a user stored in the clearance environment. def signed_in? session.signed_in? end # The user currently stored in the clearance environment. def current_user session.current_user end end end