permissive 0.0.1 → 0.2.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemspec +19 -1
- data/.gitignore +3 -1
- data/CHANGELOG +0 -0
- data/README.markdown +37 -29
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/generators/permissive_migration/templates/permissive_migration.rb +0 -2
- data/lib/permissive.rb +14 -12
- data/lib/permissive/errors.rb +4 -0
- data/lib/permissive/has_permissions.rb +153 -0
- data/lib/permissive/permission.rb +12 -30
- data/lib/permissive/permission_definition.rb +94 -0
- data/spec/has_permissions_spec.rb +326 -0
- data/spec/rcov.opts +2 -1
- data/spec/spec_helper.rb +2 -22
- metadata +23 -16
- data/README.markdown.html +0 -191
- data/lib/permissive/acts_as_permissive.rb +0 -134
- data/lib/permissive/permissions.rb +0 -29
- data/spec/acts_as_permissive_spec.rb +0 -192
- data/spec/permissions_spec.rb +0 -44
data/.gemspec
CHANGED
@@ -19,7 +19,25 @@ Gem::Specification.new do |s|
|
|
19
19
|
"README.markdown"
|
20
20
|
]
|
21
21
|
s.files = [
|
22
|
-
"
|
22
|
+
".gemspec",
|
23
|
+
".gitignore",
|
24
|
+
"MIT-LICENSE",
|
25
|
+
"README.markdown",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"generators/permissive_migration/USAGE",
|
29
|
+
"generators/permissive_migration/permissive_migration_generator.rb",
|
30
|
+
"generators/permissive_migration/templates/permissive_migration.rb",
|
31
|
+
"lib/permissive.rb",
|
32
|
+
"lib/permissive/acts_as_permissive.rb",
|
33
|
+
"lib/permissive/permission.rb",
|
34
|
+
"lib/permissive/permissions.rb",
|
35
|
+
"rails/init.rb",
|
36
|
+
"spec/acts_as_permissive_spec.rb",
|
37
|
+
"spec/permissions_spec.rb",
|
38
|
+
"spec/rcov.opts",
|
39
|
+
"spec/spec.opts",
|
40
|
+
"spec/spec_helper.rb"
|
23
41
|
]
|
24
42
|
s.homepage = %q{http://github.com/flipsasser/permissive}
|
25
43
|
s.rdoc_options = ["--charset=UTF-8"]
|
data/.gitignore
CHANGED
data/CHANGELOG
ADDED
File without changes
|
data/README.markdown
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
Permissive gives your ActiveRecord models granular permission support
|
2
2
|
=
|
3
|
-
Permissive
|
4
|
-
|
5
|
-
|
3
|
+
Permissive makes it trivial to add complex permission granting and checking
|
4
|
+
to your applications using ActiveRecord. It combines a model-based permissions
|
5
|
+
system with bitmasking to create a flexible approach to maintaining permissions
|
6
|
+
on your models. It supports an easy-to-use set of methods for accessing and
|
6
7
|
determining permissions, including some fun metaprogramming.
|
7
8
|
|
8
9
|
Installation
|
@@ -25,21 +26,30 @@ Installation
|
|
25
26
|
Usage
|
26
27
|
-
|
27
28
|
|
28
|
-
First, define a few permissions
|
29
|
+
First, define a few permissions on an ActiveRecord::Base subclass. You define them using the following simple, block-based API:
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
class User < ActiveRecord::Base
|
32
|
+
has_permissions do
|
33
|
+
to :manage_games, 0
|
34
|
+
to :control_rides, 1
|
35
|
+
to :punch, 2
|
36
|
+
end
|
36
37
|
end
|
37
38
|
|
39
|
+
The best practice is to name them in a verb format that follows this pattern: "Object can `do_action_name`".
|
40
|
+
|
41
|
+
Permission values (the second argument in `to`) need to be int values counting up from zero. We use ints because Permissive uses bit
|
42
|
+
masking to keep permissions data compact and performant.
|
43
|
+
|
38
44
|
And that's all it takes to configure permissions! Now that we have them, let's grant them to a model or two:
|
39
45
|
|
40
46
|
class Employee < ActiveRecord::Base
|
41
|
-
|
42
|
-
|
47
|
+
has_permissions, :on => :companies do
|
48
|
+
to :manage_games, 0
|
49
|
+
to :control_rides, 1
|
50
|
+
to :punch, 2
|
51
|
+
end
|
52
|
+
validates_presence_of :first_name, :last_name
|
43
53
|
end
|
44
54
|
|
45
55
|
class Company < ActiveRecord::Base
|
@@ -59,8 +69,9 @@ Easy-peasy, right? Let's try granting a few permissions:
|
|
59
69
|
@james.can?(:manage_games, :on => @adventureland) #=> true
|
60
70
|
|
61
71
|
# We can also use the metaprogramming syntax:
|
62
|
-
@james.
|
63
|
-
@james.
|
72
|
+
@james.can_manage_games_in! @adventureland
|
73
|
+
@james.can_manage_games_in? @adventureland #=> true
|
74
|
+
@james.can_control_rides_in? @adventureland #=> false
|
64
75
|
|
65
76
|
# We can check for multiple permissions, too:
|
66
77
|
@james.can?(:manage_games, :control_rides) #=> false
|
@@ -69,17 +80,20 @@ Easy-peasy, right? Let's try granting a few permissions:
|
|
69
80
|
|
70
81
|
# Scoping can be done through any object
|
71
82
|
@frigo.can!(:punch, :on => @james)
|
72
|
-
@frigo.
|
83
|
+
@frigo.can_punch? @james #=> true
|
73
84
|
|
74
85
|
# And the permissions aren't reciprocal
|
75
|
-
@james.
|
86
|
+
@james.can_punch? @frigo #=> false
|
76
87
|
|
77
88
|
# Of course, we can grant global (non-scoped) permissions, too:
|
78
|
-
@frigo.
|
89
|
+
@frigo.can_control_rides!
|
79
90
|
@frigo.can_control_rides? #=> true
|
80
91
|
|
92
|
+
# And we can grant permissions global to a class:
|
93
|
+
@frigo.can_control_rides_in! Company
|
94
|
+
|
81
95
|
# BUT! Global permissions don't override scoped permissions.
|
82
|
-
@frigo.
|
96
|
+
@frigo.can_control_rides_in?(@adventureland) #=> false
|
83
97
|
|
84
98
|
# Likewise, scoped permissions don't bubble up globally:
|
85
99
|
@james.can_manage_games? #=> false
|
@@ -90,6 +104,10 @@ Easy-peasy, right? Let's try granting a few permissions:
|
|
90
104
|
# We can revoke all permissions, in any scope, too:
|
91
105
|
@frigo.revoke(:all)
|
92
106
|
|
107
|
+
# And revoking does the fun meta thing, too:
|
108
|
+
@frigo.cannot_punch!(@james)
|
109
|
+
@frigo.can_punch? @james #=> flase
|
110
|
+
|
93
111
|
And that's it!
|
94
112
|
|
95
113
|
Scoping
|
@@ -128,17 +146,7 @@ which might yield something like
|
|
128
146
|
# and
|
129
147
|
@employee.can_control_rides_in_company @adventureland
|
130
148
|
|
131
|
-
|
132
|
-
|
133
|
-
@james.can_punch? @frigo
|
134
|
-
@frigo.can!(:control_rides, :in => @adventureland)
|
135
|
-
|
136
|
-
Meta-programmed methods for granting and revoking would be cool, too:
|
137
|
-
|
138
|
-
@james.can_punch! @frigo
|
139
|
-
@frigo.cannot_control_rides_in! @adventureland
|
140
|
-
|
141
|
-
And while we're on the subject of metaprogramming, let's add some OR-ing to the whole thing:
|
149
|
+
Let's add some OR-ing to the whole thing:
|
142
150
|
|
143
151
|
@james.can_control_rides_or_manage_games_in? @adventureland
|
144
152
|
|
data/Rakefile
CHANGED
@@ -15,7 +15,7 @@ namespace :spec do
|
|
15
15
|
Spec::Rake::SpecTask.new(:rcov) do |t|
|
16
16
|
t.spec_files = FileList['spec/**/*.rb']
|
17
17
|
t.rcov = true
|
18
|
-
t.rcov_opts = ['--exclude', '
|
18
|
+
t.rcov_opts = ['--exclude', 'spec/*,gems/*']
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -30,7 +30,7 @@ begin
|
|
30
30
|
determining permissions, including some fun metaprogramming.}
|
31
31
|
gemspec.email = "flip@x451.com"
|
32
32
|
gemspec.homepage = "http://github.com/flipsasser/permissive"
|
33
|
-
gemspec.authors = ["Flip Sasser"
|
33
|
+
gemspec.authors = ["Flip Sasser"]
|
34
34
|
end
|
35
35
|
rescue LoadError
|
36
36
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.2.0.alpha
|
@@ -6,12 +6,10 @@ class InstallPermissive < ActiveRecord::Migration
|
|
6
6
|
t.integer :scoped_object_id
|
7
7
|
t.string :scoped_object_type, :limit => 32
|
8
8
|
t.integer :mask, :default => 0
|
9
|
-
t.integer :grant_mask, :default => 0
|
10
9
|
end
|
11
10
|
add_index :permissive_permissions, [:permitted_object_id, :permitted_object_type], :name => 'permissive_permitted'
|
12
11
|
add_index :permissive_permissions, [:scoped_object_id, :scoped_object_type], :name => 'permissive_scoped'
|
13
12
|
add_index :permissive_permissions, :mask, :name => 'permissive_masks'
|
14
|
-
add_index :permissive_permissions, :grant_mask, :name => 'permissive_grant_masks'
|
15
13
|
end
|
16
14
|
|
17
15
|
def self.down
|
data/lib/permissive.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
-
require 'permissive/
|
2
|
-
require 'permissive/
|
3
|
-
require 'permissive/permissions'
|
1
|
+
require 'permissive/errors'
|
2
|
+
require 'permissive/has_permissions'
|
4
3
|
|
5
4
|
module Permissive
|
6
|
-
@@strong = false
|
7
|
-
|
8
|
-
def self.strong
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.strong=(new_strong)
|
13
|
-
|
14
|
-
end
|
5
|
+
# @@strong = false
|
6
|
+
#
|
7
|
+
# def self.strong
|
8
|
+
# @@strong
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# def self.strong=(new_strong)
|
12
|
+
# @@strong = !!new_strong
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
autoload(:Permission, 'permissive/permission')
|
16
|
+
autoload(:PermissionDefinition, 'permissive/permission_definition')
|
15
17
|
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module Permissive
|
2
|
+
module HasPermissions
|
3
|
+
module ClassMethods
|
4
|
+
def self.extended(base)
|
5
|
+
|
6
|
+
end
|
7
|
+
|
8
|
+
def has_permissions(options = {}, &block)
|
9
|
+
options.assert_valid_keys(:on)
|
10
|
+
|
11
|
+
# Define a permissions method. This will track scoped or global
|
12
|
+
# permission levels, depending on how you define them.
|
13
|
+
class_eval do
|
14
|
+
def self.permissions
|
15
|
+
@permissions ||= {}
|
16
|
+
end
|
17
|
+
end unless respond_to?(:permissions)
|
18
|
+
|
19
|
+
include InstanceMethods
|
20
|
+
|
21
|
+
has_many :permissions, :class_name => 'Permissive::Permission', :as => :permitted_object do
|
22
|
+
def can!(*args)
|
23
|
+
options = args.extract_options!
|
24
|
+
options.assert_valid_keys(:on, :reset)
|
25
|
+
permission_matcher = case options[:on]
|
26
|
+
when ActiveRecord::Base
|
27
|
+
permission = proxy_owner.permissions.find_or_initialize_by_scoped_object_id_and_scoped_object_type(options[:on].id, options[:on].class.name)
|
28
|
+
when Class
|
29
|
+
permission = proxy_owner.permissions.find_or_initialize_by_scoped_object_id_and_scoped_object_type(nil, options[:on].name)
|
30
|
+
when String, Symbol
|
31
|
+
class_name = Permissive::PermissionDefinition.interpolate_scope(proxy_owner.class, options[:on])
|
32
|
+
permission = proxy_owner.permissions.find_or_initialize_by_scoped_object_id_and_scoped_object_type(nil, class_name)
|
33
|
+
else
|
34
|
+
permission = Permissive::Permission.find_or_initialize_by_permitted_object_id_and_permitted_object_type_and_scoped_object_id_and_scoped_object_type(proxy_owner.id, proxy_owner.class.to_s, nil, nil)
|
35
|
+
end
|
36
|
+
if options[:reset]
|
37
|
+
permission.mask = 0
|
38
|
+
end
|
39
|
+
bits_for(options[:on], args).each do |bit|
|
40
|
+
unless permission.mask & bit != 0
|
41
|
+
permission.mask = permission.mask | bit
|
42
|
+
end
|
43
|
+
end
|
44
|
+
permission.save!
|
45
|
+
permission
|
46
|
+
end
|
47
|
+
|
48
|
+
def can?(*args)
|
49
|
+
options = args.extract_options!
|
50
|
+
options.assert_valid_keys(:in, :on)
|
51
|
+
options[:on] ||= options.delete(:in)
|
52
|
+
!on(options[:on]).granted(bits_for(options[:on], args)).empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
def revoke(*args)
|
56
|
+
options = args.extract_options!
|
57
|
+
if args.length == 1 && args.first == :all
|
58
|
+
on(options[:on]).destroy_all
|
59
|
+
else
|
60
|
+
bits = bits_for(options[:on], args)
|
61
|
+
on(options[:on]).each do |permission|
|
62
|
+
bits.each do |bit|
|
63
|
+
if permission.mask & bit
|
64
|
+
permission.mask = permission.mask ^ bit
|
65
|
+
end
|
66
|
+
end
|
67
|
+
permission.save!
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def bits_for(scope, permissions)
|
73
|
+
on = PermissionDefinition.normalize_scope(proxy_owner.class, scope)
|
74
|
+
permissions.map do |permission|
|
75
|
+
proxy_owner.class.permissions[on].try(:permissions).try(:[], permission.to_s.underscore.gsub('/', '_').to_sym) || raise(Permissive::InvalidPermissionError.new("#{proxy_owner.class.name} does not have a#{'n' if permission.to_s[0, 1].downcase =~ /[aeiou]/} #{permission} permission#{" on #{on}" if on}"))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
private :bits_for
|
79
|
+
end
|
80
|
+
|
81
|
+
delegate :can!, :can?, :revoke, :to => :permissions
|
82
|
+
|
83
|
+
permission_definition = Permissive::PermissionDefinition.define(self, options, &block)
|
84
|
+
|
85
|
+
permission_setter = options[:on].nil? || options[:on] == :global ? 'permissions=' : "#{options[:on].to_s.singularize}_permissions="
|
86
|
+
class_eval <<-eoc
|
87
|
+
def #{permission_setter}(values)
|
88
|
+
if values.all? {|value| value.is_a?(String) || value.is_a?(Symbol)}
|
89
|
+
can!(values, :reset => true, :on => #{options[:on].inspect})
|
90
|
+
else
|
91
|
+
super
|
92
|
+
end
|
93
|
+
end
|
94
|
+
eoc
|
95
|
+
|
96
|
+
|
97
|
+
# Oh that's right, it'll return an object.
|
98
|
+
permission_definition
|
99
|
+
end
|
100
|
+
alias :has_permission :has_permissions
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
module InstanceMethods
|
105
|
+
def method_missing(method, *args)
|
106
|
+
if method.to_s =~ /^can(not){0,1}_([^\?]+)(\?|!)$/
|
107
|
+
revoke = $1 == "not"
|
108
|
+
permissions = $2
|
109
|
+
setter = $3 == "!"
|
110
|
+
options = args.extract_options!
|
111
|
+
options[:on] ||= args.pop
|
112
|
+
if permissions =~ /_(on|in)$/
|
113
|
+
permissions.chomp!("_#{$1}")
|
114
|
+
end
|
115
|
+
if options[:on]
|
116
|
+
scope = Permissive::PermissionDefinition.normalize_scope(self.class, options[:on])
|
117
|
+
else
|
118
|
+
scope = :global
|
119
|
+
end
|
120
|
+
permissions = permissions.split('_and_')
|
121
|
+
if permissions.all? {|permission| self.class.permissions[scope].permissions.has_key?(permission.downcase.to_sym) }
|
122
|
+
if revoke
|
123
|
+
class_eval <<-end_eval
|
124
|
+
def #{method}(scope = nil)
|
125
|
+
revoke(#{[permissions, args].flatten.join(', ').inspect}, :on => scope)
|
126
|
+
end
|
127
|
+
end_eval
|
128
|
+
return can!(*[permissions, options].flatten)
|
129
|
+
elsif setter
|
130
|
+
class_eval <<-end_eval
|
131
|
+
def #{method}(scope = nil)
|
132
|
+
can!(#{[permissions, args].flatten.join(', ').inspect}, :on => scope)
|
133
|
+
end
|
134
|
+
end_eval
|
135
|
+
return can!(*[permissions, options].flatten)
|
136
|
+
else
|
137
|
+
class_eval <<-end_eval
|
138
|
+
def #{method}(scope = nil)
|
139
|
+
can?(#{[permissions, args].flatten.join(', ').inspect}, :on => scope)
|
140
|
+
end
|
141
|
+
end_eval
|
142
|
+
return can?(*[permissions, options].flatten)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
super
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
if defined?(ActiveRecord::Base)
|
152
|
+
ActiveRecord::Base.extend Permissive::HasPermissions::ClassMethods
|
153
|
+
end
|
@@ -4,40 +4,22 @@ module Permissive
|
|
4
4
|
attr_writer :grant_template, :template
|
5
5
|
belongs_to :permitted_object, :polymorphic => true
|
6
6
|
belongs_to :scoped_object, :polymorphic => true
|
7
|
+
named_scope :granted, lambda {|permissions|
|
8
|
+
{:conditions => permissions.map{|bit| "mask & #{bit}"}.join(' AND ')}
|
9
|
+
}
|
7
10
|
named_scope :on, lambda {|scoped_object|
|
8
|
-
|
9
|
-
|
11
|
+
case scoped_object
|
12
|
+
when ActiveRecord::Base
|
13
|
+
{:conditions => {:scoped_object_id => scoped_object.id, :scoped_object_type => scoped_object.class.to_s}}
|
14
|
+
when Class
|
15
|
+
{:conditions => {:scoped_object_id => nil, :scoped_object_type => scoped_object.name}}
|
16
|
+
when Symbol
|
17
|
+
{:conditions => {:scoped_object_id => nil, :scoped_object_type => scoped_object.to_s.classify}}
|
10
18
|
else
|
11
|
-
{:conditions =>
|
19
|
+
{:conditions => {:scoped_object_id => nil, :scoped_object_type => nil}}
|
12
20
|
end
|
13
21
|
}
|
14
22
|
set_table_name :permissive_permissions
|
15
|
-
validates_presence_of :
|
16
|
-
|
17
|
-
class << self
|
18
|
-
# Use this anywhere!
|
19
|
-
def bit_for(permission)
|
20
|
-
Permissive::Permissions.hash[permission.to_s.downcase.to_sym] || 0
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
def before_save
|
26
|
-
# Save permission templates or "Roles"
|
27
|
-
if @grant_template
|
28
|
-
grant_mask = @grant_template
|
29
|
-
end
|
30
|
-
if @template
|
31
|
-
mask = @template
|
32
|
-
end
|
33
|
-
|
34
|
-
# If Permissive is set to be seriously intense about who can grant what to
|
35
|
-
# whom, it makes sure no bits on the grant_mask exceed those of the
|
36
|
-
# permission mask
|
37
|
-
# TODO: You know ... this.
|
38
|
-
# if grant_mask && Permissive.strong
|
39
|
-
# grant_mask = grant_mask & mask
|
40
|
-
# end
|
41
|
-
end
|
23
|
+
validates_presence_of :mask, :permitted_object
|
42
24
|
end
|
43
25
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# TODO: Abstract this module more later
|
2
|
+
module Permissive
|
3
|
+
class PermissionDefinition
|
4
|
+
class << self
|
5
|
+
def define(model, options, &block)
|
6
|
+
options.assert_valid_keys(:on)
|
7
|
+
options = {:on => :global}.merge(options)
|
8
|
+
|
9
|
+
unless options[:on] == :global
|
10
|
+
options[:on] = normalize_scope(model, options[:on])
|
11
|
+
end
|
12
|
+
permission_definition = model.permissions[options[:on]] ||= Permissive::PermissionDefinition.new(model, options)
|
13
|
+
if block_given?
|
14
|
+
permission_definition.instance_eval(&block)
|
15
|
+
end
|
16
|
+
permission_definition
|
17
|
+
end
|
18
|
+
|
19
|
+
def interpolate_scope(model, scope)
|
20
|
+
attempted_scope = scope.to_s.singularize.classify
|
21
|
+
model_module = model.name.to_s.split('::')
|
22
|
+
model_module.pop
|
23
|
+
model_module = model_module.join('::')
|
24
|
+
if (model_module.blank? ? Object : Object.const_get(model_module)).const_defined?(attempted_scope)
|
25
|
+
[model_module, attempted_scope].join('::')
|
26
|
+
else
|
27
|
+
scope.to_s.classify
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def normalize_scope(model, scope)
|
32
|
+
case scope
|
33
|
+
when Class
|
34
|
+
scope.name.tableize
|
35
|
+
when String, Symbol
|
36
|
+
interpolate_scope(model, scope).to_s.tableize
|
37
|
+
else
|
38
|
+
:global
|
39
|
+
end.to_s.gsub('/', '_').to_sym
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def can(name, value = nil)
|
44
|
+
if value
|
45
|
+
to(name, value)
|
46
|
+
end
|
47
|
+
name = name.to_s.downcase.to_sym
|
48
|
+
roles[@role].push(name) unless roles[@role].include?(name)
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize(model, options = {})
|
52
|
+
options.assert_valid_keys(:on)
|
53
|
+
@options = options
|
54
|
+
@model = model.name
|
55
|
+
end
|
56
|
+
|
57
|
+
def model
|
58
|
+
@model.constantize
|
59
|
+
end
|
60
|
+
|
61
|
+
def on(class_name, &block)
|
62
|
+
Permissive::PermissionDefinition.define(model, @options.merge(:on => class_name), &block)
|
63
|
+
end
|
64
|
+
|
65
|
+
def permission(name, value)
|
66
|
+
unless value.is_a?(Numeric)
|
67
|
+
raise Permissive::PermissionError.new("Permissions must be integers or longs. Strings, symbols, and floats are not currently supported.")
|
68
|
+
end
|
69
|
+
permissions[name.to_s.downcase.to_sym] = 2 ** value
|
70
|
+
end
|
71
|
+
alias :to :permission
|
72
|
+
|
73
|
+
def permissions
|
74
|
+
@permissions ||= {}
|
75
|
+
end
|
76
|
+
|
77
|
+
def role(name, &block)
|
78
|
+
@role = name.to_s.to_sym
|
79
|
+
roles[@role] ||= []
|
80
|
+
instance_eval(&block)
|
81
|
+
unless model.instance_methods.include?('role=')
|
82
|
+
model.class_eval do
|
83
|
+
def role=(role_name)
|
84
|
+
self.permissions = self.class.permissions[:global].roles[role_name.to_s.downcase.to_sym]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def roles
|
91
|
+
@roles ||= {}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|