Permalink
Browse files

Merge pull request #2 from mcrowe/configure-subject-class-name

Allow the subject class name to be customized
  • Loading branch information...
mcrowe committed May 11, 2012
2 parents 2e6d599 + 52427e4 commit 7b5a92923031075ba4b8090874c373d0a0e7bb2c
View
@@ -2,7 +2,7 @@
[![Build Status](https://secure.travis-ci.org/mcrowe/roleable.png?branch=master)](http://travis-ci.org/mcrowe/roleable)
-A flexible user-roles solution for active-record-backed Rails 3 applications. Allows for multiple roles scoped to instances of any model, as well as global roles (admin, for example).
+A flexible roles solution for active-record-backed Rails 3 applications. Allows for multiple roles scoped to instances of any model, as well as global roles (admin, for example).
Roleable is designed to be ultra simple and obvious, letting you build upon it to satisfy your needs. It is also designed to be efficient: using database indices, and well-crafted queries so that it can handle a huge number of roles.
@@ -18,19 +18,19 @@ And then execute:
$ bundle
-Run the generator to create the `Role` and `UserRole` models and migrations:
+Run the generator to create the `Role` and `AppliedRole` models, migrations, and a configuration initializer:
$ rails g roleable:install
And then run the migrations:
$ rake db:migrate
-(This will create the `roles` and `user_roles` tables, together with the appropriate database indices.)
+(This will create the `roles` and `applied_roles` tables, together with the appropriate database indices.)
## Setup
-Include `Roleable::Subject` into your user (subject) model, e.g.:
+Include `Roleable::Subject` into your subject model, e.g.:
```ruby
class User < ActiveRecord::Base
@@ -39,7 +39,7 @@ class User < ActiveRecord::Base
end
```
-Include `Roleable::Resource` into any models you want to relate a user role to (resource), e.g.:
+Include `Roleable::Resource` into any models you want to relate a subject role to (resource), e.g.:
```ruby
class Page < ActiveRecord::Base
@@ -108,10 +108,20 @@ user.roles_for_resource(nil)
### Resource
-Find users with a given role:
+Find subjects (users) with a given role:
```ruby
-page.users_with_role(:editor)
+page.subjects_with_role(:editor)
+```
+
+## Customization
+
+By default, roleable assumes that your subject model is called `User`. You can customize this by modifying the generated configuration intializer located at `config/initializers/roleable.rb`, e.g.:
+
+```ruby
+Roleable.configure do |config|
+ config.subject_class_name = 'principle'
+end
```
Find users matching _any_ of a list of roles:
@@ -1,2 +1,2 @@
Description:
- The roleable:install generator creates `Role` and `UserRole` models, and generates the necessary migrations to create their database tables.
+ The roleable:install generator creates `Role` and `AppliedRole` models, and generates the necessary migrations to create their database tables.
@@ -6,11 +6,12 @@ class InstallGenerator < Rails::Generators::Base
include Rails::Generators::Migration
source_root File.expand_path('../templates', __FILE__)
- desc 'Generates a role and a user_role model, along with migrations for their tables.'
+ desc 'Generates a role and a applied_role model, along with migrations for their tables.'
def generate_install
copy_file 'role.rb', 'app/models/role.rb'
- copy_file 'user_role.rb', 'app/models/user_role.rb'
- migration_template 'migration.rb', 'db/migrate/roleable_create_roles_and_user_roles.rb'
+ copy_file 'applied_role.rb', 'app/models/applied_role.rb'
+ copy_file 'initializer.rb', 'config/initializers/roleable.rb'
+ migration_template 'migration.rb', 'db/migrate/roleable_create_roles_and_applied_roles.rb'
end
def self.next_migration_number(path)
@@ -0,0 +1,5 @@
+class AppliedRole < ActiveRecord::Base
+
+ extend Roleable::AppliedRole
+
+end
@@ -0,0 +1,4 @@
+Roleable.configure do |config|
+ # Uncomment to customize the subject class (default: 'User').
+ # config.subject_class_name = 'Subject'
+end
@@ -1,21 +1,20 @@
-class RoleableCreateRolesAndUserRoles < ActiveRecord::Migration
+class RoleableCreateRolesAndAppliedRoles < ActiveRecord::Migration
def change
create_table :roles do |t|
t.string :name
t.timestamps
end
- create_table :user_roles do |t|
- t.references :user
+ create_table :applied_roles do |t|
+ t.references :subject
t.references :role
t.references :resource, :polymorphic => true
t.timestamps
end
- add_index :user_roles, :user_id
- add_index :user_roles, :role_id
- add_index :user_roles, [:resource_type, :resource_id]
+ add_index :applied_roles, :subject_id
+ add_index :applied_roles, [:resource_type, :resource_id]
end
end
@@ -1,5 +0,0 @@
-class UserRole < ActiveRecord::Base
-
- extend Roleable::UserRole
-
-end
View
@@ -2,4 +2,17 @@
require 'roleable/subject'
require 'roleable/resource'
require 'roleable/role'
-require 'roleable/user_role'
+require 'roleable/applied_role'
+require 'roleable/configuration'
+
+module Roleable
+
+ def self.configuration
+ @configuration ||= Roleable::Configuration.new
+ end
+
+ def self.configure
+ yield configuration if block_given?
+ end
+
+end
@@ -1,15 +1,15 @@
-module Roleable::UserRole
+module Roleable::AppliedRole
def self.extended(base)
- base.belongs_to :user
+ base.belongs_to :subject, :class_name => Roleable.configuration.subject_class_name
base.belongs_to :role
base.belongs_to :resource, :polymorphic => true
- base.attr_accessible :role, :user, :resource
+ base.attr_accessible :role, :subject_id, :resource
end
- def with_user(user)
- where(:user_id => user && user.id)
+ def with_subject(subject)
+ where(:subject_id => subject && subject.id)
end
def with_resource(resource)
@@ -35,14 +35,14 @@ def with_resource_class(resource_class)
#
# Returns the record if it was saved, otherwise nil.
def create_if_unique!(attributes)
- user_role = new(attributes)
-
- record_attributes = user_role.attributes.reject do |k, v|
+ applied_role = new(attributes)
+
+ record_attributes = applied_role.attributes.reject do |k, v|
%w(id updated_at created_at).include?(k)
end
- if !exists?(record_attributes) && user_role.save
- user_role
+ if !exists?(record_attributes) && applied_role.save
+ applied_role
else
nil
end
@@ -0,0 +1,9 @@
+class Roleable::Configuration
+
+ attr_accessor :subject_class_name
+
+ def initialize
+ @subject_class_name = 'User'
+ end
+
+end
View
@@ -1,19 +1,26 @@
module Roleable::Resource
def self.included(base)
- base.has_many :user_roles, :as => :resource
+ base.has_many :applied_roles, :as => :resource
end
# Return a list of users that have the given role for this resource.
# If a list of role names is given, return users with any of those roles for this resource.
#
# ==== Examples
#
- # page.users_with_role(:editor) # => [user1, user2, ...]
- # page.users_with_role([:editor, :author]) # => [user1, user2, ...]
+ # page.subjects_with_role(:editor) # => [user1, user2, ...]
+ # page.subjects_with_role([:editor, :author]) # => [user1, user2, ...]
#
- def users_with_role(role_name)
- User.joins(:user_roles).merge(::UserRole.with_role_name(role_name).with_resource(self))
+ def subjects_with_role(role_name)
+ subject_class.joins(:applied_roles).
+ merge( ::AppliedRole.with_role_name(role_name).with_resource(self) )
+ end
+
+ private
+
+ def subject_class
+ Roleable.configuration.subject_class_name.classify.constantize
end
end
View
@@ -1,7 +1,7 @@
module Roleable::Role
def self.extended(base)
- base.has_many :user_roles
+ base.has_many :applied_roles
base.attr_accessible :name
end
View
@@ -1,12 +1,12 @@
module Roleable::Subject
def self.included(base)
- base.has_many :user_roles
+ base.has_many :applied_roles, :foreign_key => 'subject_id'
end
- # Add a role to the user scoped to the given resource or global if no resource given.
+ # Add a role to the subject scoped to the given resource or global if no resource given.
#
- # Does nothing if a role with the given name doesn't exist, or if the user already has
+ # Does nothing if a role with the given name doesn't exist, or if the subject already has
# the given role.
#
# ==== Examples
@@ -17,26 +17,28 @@ def self.included(base)
def add_role(role_name, resource = nil)
role = ::Role.find_by_name(role_name) or return
- ::UserRole.create_if_unique!(:user => self, :role => role, :resource => resource)
+ ::AppliedRole.create_if_unique!(:subject_id => self.id, :role => role, :resource => resource)
end
- # Check if the user has the given role for the given resource, or if they have the role globally
+ # Check if the subject has the given role for the given resource, or if they have the role globally
# if no resource given.
#
- # Returns <tt>true</tt> if the user has the role, <tt>false</tt> otherwise.
+ # Returns <tt>true</tt> if the subject has the role, <tt>false</tt> otherwise.
#
# ==== Examples
#
# user.has_role?(:editor, page) # True if the user has the editor role for page
# user.has_role?(:admin) # True if the user has a global admin role
#
def has_role?(role_name, resource = nil)
- user_roles = ::UserRole.with_user(self).with_resource(resource).with_role_name(role_name)
-
- user_roles.exists?
+ ::AppliedRole.
+ with_subject(self).
+ with_resource(resource).
+ with_role_name(role_name).
+ exists?
end
- # Remove the given role from the user for the given resource, or globally if no resource given.
+ # Remove the given role from the subject for the given resource, or globally if no resource given.
#
# Returns <tt>true</tt> if the role was found and deleted, <tt>false</tt> otherwise.
#
@@ -46,35 +48,35 @@ def has_role?(role_name, resource = nil)
# user.remove_role(:admin) # Remove the global admin role from the user
#
def remove_role(role_name, resource = nil)
- user_roles = ::UserRole.with_user(self).with_resource(resource).with_role_name(role_name)
+ applied_roles = ::AppliedRole.with_subject(self).with_resource(resource).with_role_name(role_name)
- deleted_count = user_roles.delete_all
+ deleted_count = applied_roles.delete_all
deleted_count > 0
end
- # Return a list of resources of the given class, for which the user has the given role.
- # If passed an array or roles, returns resources for which the user has any of the roles.
+ # Return a list of resources of the given class, for which the subject has the given role.
+ # If passed an array or roles, returns resources for which the subject has any of the roles.
#
# ==== Examples
#
# user.resources_with_role(:editor, Page) # => [page1, page2, ...]
# user.resources_with_role([:editor, :author], Page) # => [page1, page2, ...]
#
def resources_with_role(role_name, resource_class)
- user_roles = ::UserRole.with_user(self).with_role_name(role_name).with_resource_class(resource_class)
- resource_class.includes(:user_roles).merge(user_roles)
+ applied_roles = ::AppliedRole.with_subject(self).with_role_name(role_name).with_resource_class(resource_class)
+ resource_class.includes(:applied_roles).merge(applied_roles)
end
- # Return a list of roles that the user has for the given resource.
+ # Return a list of roles that the subject has for the given resource.
#
# ==== Examples
#
# user.roles_for_resource(page) # => [role1, role2, ...]
#
def roles_for_resource(resource)
- user_roles = ::UserRole.with_user(self).with_resource(resource)
- ::Role.includes(:user_roles).merge(user_roles)
+ applied_roles = ::AppliedRole.with_subject(self).with_resource(resource)
+ ::Role.includes(:applied_roles).merge(applied_roles)
end
end
Oops, something went wrong.

0 comments on commit 7b5a929

Please sign in to comment.