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
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,34 @@ For example:
config.password_strategy = Clearance::PasswordStrategies::SHA1
# 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
--------------------------
Expand Down
2 changes: 1 addition & 1 deletion gemfiles/3.1.4.gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PATH
remote: /home/mike/clearance
remote: /Users/gabe/thoughtbot/open-source/clearance
specs:
clearance (0.16.2)
diesel (~> 0.1.5)
Expand Down
2 changes: 1 addition & 1 deletion gemfiles/3.2.3.gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PATH
remote: /home/mike/clearance
remote: /Users/gabe/thoughtbot/open-source/clearance
specs:
clearance (0.16.2)
diesel (~> 0.1.5)
Expand Down
1 change: 1 addition & 0 deletions lib/clearance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
require 'clearance/user'
require 'clearance/engine'
require 'clearance/password_strategies'
require 'clearance/constraints'
2 changes: 2 additions & 0 deletions lib/clearance/constraints.rb
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ def signed_in?
current_user.present?
end

def signed_out?
! signed_in?
end

def current_user
@current_user ||= with_remember_token do |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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
env = env_with_remember_token("bogus")

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

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

Expand Down
17 changes: 17 additions & 0 deletions spec/support/request_with_remember_token.rb
Original file line number Diff line number Diff line change
@@ -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.