Skip to content

Instantly share code, notes, and snippets.

@mallain
Created September 1, 2010 15:41
Show Gist options
  • Save mallain/560883 to your computer and use it in GitHub Desktop.
Save mallain/560883 to your computer and use it in GitHub Desktop.
class Ability
# Include module CanCan
include CanCan::Ability
###############
# Constructor #
###############
def initialize(user)
# Instanciate or retrieves arg user
user ||= User.new
# Role admin ?
if user.role? :admin
# Manage all resources
can :manage, :all
elsif user.role? :poweruser
# Manage only public resources and forbidden private resources
poweruser_authorizations(user)
elsif user.role? :banned
# All resources are forbidden
banned_authorizations
end
end
##################
# Static methods #
##################
# Define CRUD actions
# Create / Read / Update / Destroy
# Return Array which contain syms
def self.crud_actions
[:create, :read, :update, :destroy]
end
# Load YML File which contain roles
def self.load_roles(file='roles.yml')
YAML.load_file("#{RAILS_ROOT}/config/#{file}")
end
# Listing application roles
# Return array which contain string
def self.roles
app_roles = Ability.load_roles
app_roles['roles']
end
# Listing public resources
# Return array which contain string
def self.public_resources
app_roles = Ability.load_roles
app_roles['public_resources']
end
# Listing private resources
# Return array which contain string
def self.private_resources
app_roles = Ability.load_roles
app_roles['private_resources']
end
# Listing admin resources
# Return array which contain string
def self.admin_resources
app_roles = Ability.load_roles
app_roles['admin_resources']
end
##################
# Public methods #
##################
# Define "can" action on user
# param action is define by a sym action CRUD (sym)
# param model : define the create action on model (string)
# param user which is the user instanciate (user)
# ex : user_can_do_an_action(:create, 'CollaboratorNumber')
def user_can_do_an_action(action, model)
can action.to_sym, model.classify.constantize
end
# Define "can" action on user with constraints of agency
# param action is define by a sym action CRUD (sym)
# param model : define the create action on model (string)
# param user which is the user instanciate (user)
# ex : user_can_do_an_action_with_constraints(:create, 'CollaboratorNumber')
def user_can_do_an_action_with_constraints(action, model, user)
can action.to_sym, model.classify.constantize do |object|
object && object.try(:agency).users.include?(user)
end
end
# Define "cannot" action on user
# param action is define by a sym action CRUD (sym)
# param model : define the create action on model (string)
# ex : user_cannot_do_an_action(:create, 'CollaboratorNumber')
def user_cannot_do_an_action(action, model)
cannot action.to_sym, model.classify.constantize
end
###################
# Private methods #
###################
protected
# Initialise poweruser_authorizations
# param user which is the user instanciate (user)
def poweruser_authorizations(user)
# Listing all public resources
Ability.public_resources.each do |resource|
# List all actions
Ability.crud_actions.each do |action|
# Allow the action with constraints sometimes
action.eql?(:create) ? user_can_do_an_action(action, resource) : user_can_do_an_action_with_constraints(action, resource, user)
end
end
# Listing all private resources
Ability.private_resources.each do |resource|
# List all actions
Ability.crud_actions.each do |action|
# Forbidden the action
user_cannot_do_an_action(action, resource)
end
end
end
# Initialise banned authorizations
# param user which is the user instanciate (user)
def banned_authorizations
# Listing public and private reources
%w(public private).each do |resource_type|
# Listing resources
Ability.admin_resources[resource_type].each do |resource|
# List all actions
Ability.crud_actions.each do |action|
# Forbidden the action
user_cannot_do_an_action(action, resource)
end
end
end
end
end
mickael@mickael-laptop:~/projects/pabd/test$ ruby unit/user_test.rb
Loaded suite unit/user_test
Started
.....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Finished in 99.327254 seconds.
629 tests, 629 assertions, 0 failures, 0 errors
roles:
- admin
- poweruser
- banned
private_resources: &private_resources
- Service
- Delivery
- Feedback
- Training
- Stage
- Assignment
- Country
- User
- Feeling
- Agency
- SubcontractType
- Division
- Skill
- Collaborator
- AccountType
- Project
- Function
- DepartureType
- Account
public_resources: &public_resources
- CollaboratorNumber
- KnowledgeManagement
- IntercoCollaborator
- DistributionDay
- Book
- ClaimCollection
- DeliveryDistribution
- BigDeal
- TroubleProject
- ArrivalCollaborator
- Pipe
- AskHelp
- FeelingAgency
- ProductionNumber
- Offer
- DepartureCollaborator
- MajorCompany
- ProductionDay
- CollaboratorFunction
- Interview
- CostNumber
- SubcontractNumber
- Prospect
- AlertCollaborator
- DayRate
- SmallCompany
admin_resources:
private: *private_resources
public: *public_resources
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test_help'
require 'factory_girl'
require 'shoulda'
require 'faker'
require "authlogic/test_case"
require 'i18n'
class ActiveSupport::TestCase
# Transactional fixtures accelerate your tests by wrapping each test method
# in a transaction that's rolled back on completion. This ensures that the
# test database remains unchanged so your fixtures don't have to be reloaded
# between every test method. Fewer database queries means faster tests.
#
# Read Mike Clark's excellent walkthrough at
# http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
#
# Every Active Record database supports transactions except MyISAM tables
# in MySQL. Turn off transactional fixtures in this case; however, if you
# don't care one way or the other, switching from MyISAM to InnoDB tables
# is recommended.
#
# The only drawback to using transactional fixtures is when you actually
# need to test transactions. Since your test is bracketed by a transaction,
# any transactions started in your code will be automatically rolled back.
self.use_transactional_fixtures = true
# Instantiated fixtures are slow, but give you @david where otherwise you
# would need people(:david). If you don't want to migrate your existing
# test cases which use the @david style and don't mind the speed hit (each
# instantiated fixtures translates to a database query per test method),
# then set this back to true.
self.use_instantiated_fixtures = false
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
#fixtures :all
end
# Redefine #t method of TranslationHelper
# With this hack, all missing translation will raise a exception
module ActionView
module Helpers
module TranslationHelper
def t(key, options = {})
options[:raise] = true
I18n.translate(scope_key_by_partial(key), options)
end
end
end
end
# Define active_authlogic into all setup
class ActionController::TestCase
setup :activate_authlogic
end
# Generate an action
# param action : define the "get" action (string)
# ex : should_get_action("index")
def should_get_action(action)
context "on GET to #{action}" do
setup do
get action
end
should_respond_with :success
should_render_with_layout
should_render_template action
should_not_set_the_flash
end
end
# Return available locales for testing into ControllerTest
def available_testing_locales
I18n.available_locales
end
# Instanciate stub objects
# param name : Describe the name of model (string)
# ex : instanciate_stub_object('feedback')
def instanciate_stub_object(name)
# Instanciate objects array
objects = []
# Instanciate first object
instance_variable_set("@#{name}".to_sym, Factory.stub(name.to_sym))
# Instanciate five objects
(1..5).each do |i|
instance_variable_set("@#{name}_#{i}".to_sym, Factory.stub(name.to_sym))
instance_variable_get("@#{name}_#{i}").id = rand(3000)
objects << instance_variable_get("@#{name}_#{i}")
end
# Find method return an instanciate object
name.classify.constantize.stubs(:find).returns(instance_variable_get("@#{name}"))
# Find method with "all" parameter will return an array of instanciate objects
name.classify.constantize.stubs(:find).with(:all, anything).returns(objects)
end
# Generate setup with parameter
# param lang : Define the default_locale (string)
# param instanciate : Define the list of objects we have to instanciate in this setup Array with Hash
# ex : generate_setup(:lang => 'fr')
# ex : generate_setup(:lang => 'en', :instanciate => ['feedback', 'claim_collection')
def generate_setup(params={:instanciate => []})
# Instanciate session
LdapConnect.any_instance.stubs(:online?).returns(true)
UserSession.create!(Factory(:user))
# Create at least one agency
Factory(:agency)
# Feedback is need everywhere
instanciate_stub_object('feedback')
# Instanciate every object included in params[:instanciate] variable
if params.has_key?(:instanciate)
params[:instanciate].each do |object|
instanciate_stub_object(object)
end
end
# Define setup locale
I18n.default_locale = params[:lang]
end
#################################
# Tests Ability #
# poweruser public resources #
#################################
# Function for Test Unit
# Checking if the object could be create by an user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_can_create_object('poweruser', "CollaboratorNumber")
def user_can_create_object(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
# Implement the test
test "user with #{role_name} role can create #{modelize.to_s} object" do
# Create an user with a specific role
user = Factory(:user, :role => role_name)
# Instanciate layer Ability
ability = Ability.new(user)
# Checking the ability
assert ability.can?(:create, modelize.new)
end
end
# Function for Test Unit
# Checking if the object could be read by an user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_can_read_object('poweruser', "CollaboratorNumber")
def user_can_read_object(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role can read #{modelize.to_s} object" do
# Create an user with a specific role
user = Factory(:user, :role => role_name)
# Instanciate layer Ability
ability = Ability.new(user)
# Instanciate object with foreign agency_id key from user
object = Factory(modelize_sym, :agency => user.agencies.first)
# Checking the ability
assert ability.can?(:read, object)
end
end
# Function for Test Unit
# Checking if the object couldn t be read by another user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_cannot_read_object_own_by_another_user('poweruser', "CollaboratorNumber")
def user_cannot_read_object_own_by_another_user(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role cannot read #{modelize.to_s} object which he doesn't own" do
# Create users with a specific role
user1 = Factory(:user, :role => role_name)
user2 = Factory(:user, :role => role_name)
# Instanciate layer Ability with an user
ability = Ability.new(user1)
# Instanciate object with foreign agency_id key from user2
object = Factory(modelize_sym, :agency => user2.agencies.first)
# Checking the !ability of user1 to manipulate the object
assert !ability.can?(:read, object)
end
end
# Function for Test Unit
# Checking if the user objects could be update by him
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_can_update_his_own_object('poweruser', "CollaboratorNumber")
def user_can_update_his_own_object(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role can update #{modelize.to_s} object which he own" do
# Create an user with a specific role
user = Factory(:user, :role => role_name)
# Instanciate layer Ability
ability = Ability.new(user)
# Instanciate object with foreign agency_id key
object = Factory(modelize_sym, :agency => user.agencies.first)
# Checking the ability
assert ability.can?(:update, object)
end
end
# Function for Test Unit
# Checking if the user objects couldn t be update by another user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_cannot_update_object_own_by_other('poweruser', "CollaboratorNumber")
def user_cannot_update_object_own_by_another_user(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role cannot update #{modelize.to_s} object which he doesn't own" do
# Create users with a specific role
user1 = Factory(:user, :role => role_name)
user2 = Factory(:user, :role => role_name)
# Instanciate layer Ability with an user
ability = Ability.new(user1)
# Instanciate object with foreign agency_id key from user2
object = Factory(modelize_sym, :agency => user2.agencies.first)
# Checking the !ability of user1 to manipulate the object
assert !ability.can?(:update, object)
end
end
# Function for Test Unit
# Checking if the user objects could be destroy by him
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_can_update_his_own_object('poweruser', "CollaboratorNumber")
def user_can_destroy_his_own_object(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role can destroy #{modelize.to_s} object which he own" do
# Create an user with a specific role
user = Factory(:user, :role => role_name)
# Instanciate layer Ability
ability = Ability.new(user)
# Instanciate object with foreign agency_id key
object = Factory(modelize_sym, :agency => user.agencies.first)
# Checking the ability
assert ability.can?(:destroy, object)
end
end
# Function for Test Unit
# Checking if the user objects could be destroy by another user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_cannot_destroy_object_own_by_another_user('poweruser', "CollaboratorNumber")
def user_cannot_destroy_object_own_by_another_user(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role cannot destroy #{modelize.to_s} object which he doesn't own" do
# Create users with a specific role
user1 = Factory(:user, :role => role_name)
user2 = Factory(:user, :role => role_name)
# Instanciate layer Ability with an user
ability = Ability.new(user1)
# Instanciate object with foreign agency_id key from user2
object = Factory(modelize_sym, :agency => user2.agencies.first)
# Checking the !ability of user1 to manipulate the object
assert !ability.can?(:destroy, object)
end
end
#################################
# Tests Ability #
# for banned user & #
# poweruser private resources #
#################################
# Cannot do any actions #
#################################
# Function for Test Unit
# Checking if the object couldn t be create by an user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_cannot_create_object('poweruser', "CollaboratorNumber")
def user_cannot_create_object(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
# Implement the test
test "user with #{role_name} role cannot create #{modelize.to_s} object" do
# Create an user with a specific role
user = Factory(:user, :role => role_name)
# Instanciate layer Ability
ability = Ability.new(user)
# Checking the ability
assert !ability.can?(:create, modelize.new)
end
end
# Function for Test Unit
# Checking if the object couldn t be read by an user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_cannot_read_object('poweruser', "CollaboratorNumber")
def user_cannot_read_object(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role cannot read #{modelize.to_s} object" do
# Create an user with a specific role
user = Factory(:user, :role => role_name)
# Instanciate layer Ability
ability = Ability.new(user)
# Instanciate object
object = Factory(modelize_sym)
# Checking the ability
assert !ability.can?(:read, object)
end
end
# Function for Test Unit
# Checking if the user objects couldn t be update by an user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_cannot_update('poweruser', "CollaboratorNumber")
def user_cannot_update_object(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role cannot update #{modelize.to_s} object" do
# Create an user with a specific role
user = Factory(:user, :role => role_name)
# Instanciate layer Ability
ability = Ability.new(user)
# Instanciate object
object = Factory(modelize_sym)
# Checking the ability
assert !ability.can?(:update, object)
end
end
# Function for Test Unit
# Checking if the user objects couldn t be destroy
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_cannot_object('poweruser', "CollaboratorNumber")
def user_cannot_destroy_object(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role cannot destroy #{modelize.to_s} object" do
# Create an user with a specific role
user = Factory(:user, :role => role_name)
# Instanciate layer Ability
ability = Ability.new(user)
# Instanciate object with foreign agency_id key
object = Factory(modelize_sym)
# Checking the ability
assert !ability.can?(:destroy, object)
end
end
# Specific Admin authorizations
#######################
# Tests Ability #
# for admin resources #
#######################
# Can do anything #
#######################
# Function for Test Unit
# Checking if the object could be read by another user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_can_read_object_own_by_another_user('poweruser', "CollaboratorNumber")
def user_can_read_object_own_by_another_user(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role can read #{modelize.to_s} object which he doesn't own" do
# Create users with a specific role
user1 = Factory(:user, :role => role_name)
# Instanciate layer Ability with an user
ability = Ability.new(user1)
# Instanciate object with foreign agency_id key from user2
object = Factory(modelize_sym)
# Checking the !ability of user1 to manipulate the object
assert ability.can?(:read, object)
end
end
# Function for Test Unit
# Checking if the user objects couldn t be update by another user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_can_update_object_own_by_other('poweruser', "CollaboratorNumber")
def user_can_update_object_own_by_another_user(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role can update #{modelize.to_s} object which he doesn't own" do
# Create users with a specific role
user1 = Factory(:user, :role => role_name)
# Instanciate layer Ability with an user
ability = Ability.new(user1)
# Instanciate object with foreign agency_id key from user2
object = Factory(modelize_sym)
# Checking the !ability of user1 to manipulate the object
assert ability.can?(:update, object)
end
end
# Function for Test Unit
# Checking if the user objects could be destroy by another user
# param role_name : define the role_name (string)
# param model : define the create action on model (string)
# ex : user_cannot_destroy_object_own_by_another_user('poweruser', "CollaboratorNumber")
def user_can_destroy_object_own_by_another_user(role_name, model)
# Classify and Constantize the string model
modelize = model.classify.constantize
modelize_sym = model.underscore.to_sym
# Implement the test
test "user with #{role_name} role can destroy #{modelize.to_s} object which he doesn't own" do
# Create users with a specific role
user1 = Factory(:user, :role => role_name)
# Instanciate layer Ability with an user
ability = Ability.new(user1)
# Instanciate object with foreign agency_id key from user2
object = Factory(modelize_sym)
# Checking the !ability of user1 to manipulate the object
assert ability.can?(:destroy, object)
end
end
require 'test_helper'
class UserTest < ActiveSupport::TestCase
subject { Factory(:user) }
should_validate_presence_of(:email, :role)
should_validate_uniqueness_of(:email)
should_have_and_belong_to_many(:agencies)
# Testing format mail
%w(foo@bar.com foo@businessdecision.com@test.com bar@foo.com).each do |mail|
test "should not save user without a formated businessdecision email #{mail}" do
user = Factory.build(:user, :email => mail)
assert !user.save, "Saved the user without a formated bd email"
end
end
# Testing roles
%w(fake_role 42 unknow test).each do |named_role|
test "should not save user without accepted role #{named_role}" do
user = Factory.build(:user, :role => named_role)
assert !user.save, "Saved the user without accepted role"
end
end
###############################
# Testing Authorizations #
# for user groups : #
# Admin / Powerusers / Banned #
###############################
########################
# Testing abilities #
# Admin authorizations #
########################
# Setting role name
role_name = 'admin'
# Testing for public & private resources
%w(public private).each do |resource_type|
Ability.admin_resources[resource_type].each do |resource|
# Create test
user_can_create_object(role_name, resource)
# Reading tests
user_can_read_object_own_by_another_user(role_name, resource)
# Update tests
user_can_update_object_own_by_another_user(role_name, resource)
# Destroy test
user_can_destroy_object_own_by_another_user(role_name, resource)
end
end
#############################
# Testing abilities #
# Powerusers authorizations #
#############################
# Setting role name
role_name = 'poweruser'
# Testing for Public resources
Ability.public_resources.each do |resource|
# Create test
user_can_create_object(role_name, resource)
# Reading tests
user_can_read_object(role_name, resource)
user_cannot_read_object_own_by_another_user(role_name, resource)
# Update tests
user_can_update_his_own_object(role_name, resource)
user_cannot_update_object_own_by_another_user(role_name, resource)
# Destroy tests
user_can_destroy_his_own_object(role_name, resource)
user_cannot_destroy_object_own_by_another_user(role_name, resource)
end
# Testing for Private resources
Ability.private_resources.each do |resource|
# Create test
user_cannot_create_object(role_name, resource)
# Reading test
user_cannot_read_object(role_name, resource)
# Update test
user_cannot_update_object(role_name, resource)
# Destroy test
user_cannot_destroy_object(role_name, resource)
end
#########################
# Testing abilities #
# Banned authorizations #
#########################
# Setting role name
role_name = 'banned'
# Testing for public & private resources
%w(public private).each do |resource_type|
Ability.admin_resources[resource_type].each do |resource|
# Create test
user_cannot_create_object(role_name, resource)
# Reading test
user_cannot_read_object(role_name, resource)
# Update test
user_cannot_update_object(role_name, resource)
# Destroy test
user_cannot_destroy_object(role_name, resource)
end
end
end
@mallain
Copy link
Author

mallain commented Sep 1, 2010

Implementation of CanCan plugin into Rails App with user groups.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment