Permalink
Browse files

Provide router constraints

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 13, 2012
1 parent e084e6b commit 3746806871b4ba3a549613ee3e800252622f7074
View
@@ -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
--------------------------
@@ -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)
@@ -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)
View
@@ -5,3 +5,4 @@
require 'clearance/user'
require 'clearance/engine'
require 'clearance/password_strategies'
+require 'clearance/constraints'
@@ -0,0 +1,2 @@
+require 'clearance/constraints/signed_in'
+require 'clearance/constraints/signed_out'
@@ -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
@@ -0,0 +1,9 @@
+module Clearance
+ module Constraints
+ class SignedOut
+ def matches?(request)
+ request.env[:clearance].signed_out?
+ end
+ end
+ end
+end
View
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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.