Skip to content

Commit

Permalink
Provide router constraints
Browse files Browse the repository at this point in the history
Adds SignedInConstraint and SignedOutConstraint, useful from the Rails
router. For example, to redirect admins to their admin dashboard as the
home page:

    constraints(SignedInConstraint.new {|user| user.admin?}) do
      root :to => 'admins/dashboard#index'
    end
  • Loading branch information
Arun Agrawal and Gabe Berke-Williams authored and mike-burns committed Jun 29, 2012
1 parent e084e6b commit 3746806
Show file tree
Hide file tree
Showing 12 changed files with 160 additions and 5 deletions.
29 changes: 28 additions & 1 deletion README.md
Expand Up @@ -210,7 +210,34 @@ For example:
config.password_strategy = Clearance::PasswordStrategies::SHA1 config.password_strategy = Clearance::PasswordStrategies::SHA1
# Blowfish # Blowfish
config.password_strategy = Clearance::PasswordStrategies::Blowfish config.password_strategy = Clearance::PasswordStrategies::Blowfish



Routing Constraints
-------------------

Clearance ships with Rails [routing constraints](http://guides.rubyonrails.org/routing.html#advanced-constraints).
These allow you to check if a user is signed in or signed out before they hit your controller - the check is moved down the stack.
You can use them like this:

SweetBlog::Application.routes.draw do
# Signed-in admin users use this root path
constraints(Clearance::Constraints::SignedIn.new {|user| user.admin?}) do
root :to => 'admins/dashboard#index'
end

# Signed-in non-admin users use this root path
constraints(Clearance::Constraints::SignedIn.new) do
root :to => 'organizations#show'
end

# Signed-out users users use this fallback root path
constraints(Clearance::Constraints::SignedOut.new) do
root :to => 'high_voltage/pages#show', :id => 'home'
end
end

Note that `Clearance::Constraints::SignedIn` yields a signed-in user object so
that you can perform additional checks.


Optional Cucumber features Optional Cucumber features
-------------------------- --------------------------
Expand Down
2 changes: 1 addition & 1 deletion gemfiles/3.1.4.gemfile.lock
@@ -1,5 +1,5 @@
PATH PATH
remote: /home/mike/clearance remote: /Users/gabe/thoughtbot/open-source/clearance
specs: specs:
clearance (0.16.2) clearance (0.16.2)
diesel (~> 0.1.5) diesel (~> 0.1.5)
Expand Down
2 changes: 1 addition & 1 deletion gemfiles/3.2.3.gemfile.lock
@@ -1,5 +1,5 @@
PATH PATH
remote: /home/mike/clearance remote: /Users/gabe/thoughtbot/open-source/clearance
specs: specs:
clearance (0.16.2) clearance (0.16.2)
diesel (~> 0.1.5) diesel (~> 0.1.5)
Expand Down
1 change: 1 addition & 0 deletions lib/clearance.rb
Expand Up @@ -5,3 +5,4 @@
require 'clearance/user' require 'clearance/user'
require 'clearance/engine' require 'clearance/engine'
require 'clearance/password_strategies' require 'clearance/password_strategies'
require 'clearance/constraints'
2 changes: 2 additions & 0 deletions lib/clearance/constraints.rb
@@ -0,0 +1,2 @@
require 'clearance/constraints/signed_in'
require 'clearance/constraints/signed_out'
28 changes: 28 additions & 0 deletions lib/clearance/constraints/signed_in.rb
@@ -0,0 +1,28 @@
module Clearance
module Constraints
class SignedIn
def initialize(&block)
@block = block || lambda { |user| true }
end

def matches?(request)
@request = request
signed_in? && current_user_fulfills_additional_requirements?
end

private

def signed_in?
@request.env[:clearance].signed_in?
end

def current_user_fulfills_additional_requirements?
@block.call(current_user)
end

def current_user
@request.env[:clearance].current_user
end
end
end
end
9 changes: 9 additions & 0 deletions lib/clearance/constraints/signed_out.rb
@@ -0,0 +1,9 @@
module Clearance
module Constraints
class SignedOut
def matches?(request)
request.env[:clearance].signed_out?
end
end
end
end
4 changes: 4 additions & 0 deletions lib/clearance/session.rb
Expand Up @@ -10,6 +10,10 @@ def signed_in?
current_user.present? current_user.present?
end end


def signed_out?
! signed_in?
end

def current_user def current_user
@current_user ||= with_remember_token do |token| @current_user ||= with_remember_token do |token|
Clearance.configuration.user_model.find_by_remember_token(token) Clearance.configuration.user_model.find_by_remember_token(token)
Expand Down
52 changes: 52 additions & 0 deletions spec/clearance/constraints/signed_in_spec.rb
@@ -0,0 +1,52 @@
require 'spec_helper'

describe Clearance::Constraints::SignedIn do
it 'returns true when user is signed in' do
user = create(:user)

signed_in_constraint = Clearance::Constraints::SignedIn.new
signed_in_constraint.matches?(request_with_remember_token(user.remember_token)).should be_true
end

it 'returns false when user is not signed in' do
signed_in_constraint = Clearance::Constraints::SignedIn.new
signed_in_constraint.matches?(request_without_remember_token).should be_false
end

it 'yields a signed-in user to a provided block' do
user = create(:user, :email => 'before@example.com')
signed_in_constraint = Clearance::Constraints::SignedIn.new do |user|
user.update_attribute(:email, 'after@example.com')
end

signed_in_constraint.matches?(request_with_remember_token(user.remember_token))
user.reload.email.should == 'after@example.com'
end

it 'does not yield a user if they are not signed in' do
user = create(:user, :email => 'before@example.com')

signed_in_constraint = Clearance::Constraints::SignedIn.new do |user|
user.update_attribute(:email, 'after@example.com')
end

signed_in_constraint.matches?(request_without_remember_token)
user.reload.email.should == 'before@example.com'
end

it 'matches if the user-provided block returns true' do
user = create(:user)

signed_in_constraint = Clearance::Constraints::SignedIn.new { |user| true }

signed_in_constraint.matches?(request_with_remember_token(user.remember_token)).should be_true
end

it 'does not match if the user-provided block returns false' do
user = create(:user)

signed_in_constraint = Clearance::Constraints::SignedIn.new { |user| false }

signed_in_constraint.matches?(request_with_remember_token(user.remember_token)).should be_false
end
end
15 changes: 15 additions & 0 deletions spec/clearance/constraints/signed_out_spec.rb
@@ -0,0 +1,15 @@
require 'spec_helper'

describe Clearance::Constraints::SignedOut do
it 'returns true when user is signed out' do
signed_out_constraint = Clearance::Constraints::SignedOut.new
signed_out_constraint.matches?(request_without_remember_token).should be_true
end

it 'returns false when user is not signed out' do
user = create(:user)

signed_out_constraint = Clearance::Constraints::SignedOut.new
signed_out_constraint.matches?(request_with_remember_token(user.remember_token)).should be_false
end
end
4 changes: 2 additions & 2 deletions spec/clearance/session_spec.rb
Expand Up @@ -18,14 +18,14 @@
env = env_with_remember_token("bogus") env = env_with_remember_token("bogus")


session = Clearance::Session.new(env) session = Clearance::Session.new(env)
session.should_not be_signed_in session.should be_signed_out
session.current_user.should be_nil session.current_user.should be_nil
end end


it "returns nil without a remember token" do it "returns nil without a remember token" do
env = env_without_remember_token env = env_without_remember_token
session = Clearance::Session.new(env) session = Clearance::Session.new(env)
session.should_not be_signed_in session.should be_signed_out
session.current_user.should be_nil session.current_user.should be_nil
end end


Expand Down
17 changes: 17 additions & 0 deletions spec/support/request_with_remember_token.rb
@@ -0,0 +1,17 @@
module RememberTokenHelpers
def request_with_remember_token(remember_token)
cookies = {'action_dispatch.cookies' => {
Clearance::Session::REMEMBER_TOKEN_COOKIE => remember_token
}}
env = { :clearance => Clearance::Session.new(cookies) }
Rack::Request.new(env)
end

def request_without_remember_token
request_with_remember_token(nil)
end
end

RSpec.configure do |config|
config.include RememberTokenHelpers
end

0 comments on commit 3746806

Please sign in to comment.