rolify 3.1.0 → 3.2.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/.travis.yml +2 -4
- data/CHANGELOG.rdoc +17 -0
- data/README.md +42 -6
- data/lib/generators/rolify/role/role_generator.rb +11 -3
- data/lib/generators/rolify/role/templates/initializer.rb +2 -1
- data/lib/generators/rolify/role/templates/role-active_record.rb +2 -0
- data/lib/generators/rolify/role/templates/role-mongoid.rb +11 -9
- data/lib/rolify.rb +13 -5
- data/lib/rolify/adapters/active_record/resource_adapter.rb +11 -4
- data/lib/rolify/adapters/active_record/role_adapter.rb +11 -4
- data/lib/rolify/adapters/active_record/scopes.rb +27 -0
- data/lib/rolify/adapters/base.rb +5 -0
- data/lib/rolify/adapters/mongoid/resource_adapter.rb +9 -5
- data/lib/rolify/adapters/mongoid/role_adapter.rb +14 -2
- data/lib/rolify/adapters/mongoid/scopes.rb +27 -0
- data/lib/rolify/finders.rb +39 -0
- data/lib/rolify/railtie.rb +1 -1
- data/lib/rolify/resource.rb +2 -1
- data/lib/rolify/role.rb +12 -2
- data/lib/rolify/version.rb +1 -1
- data/rolify.gemspec +4 -4
- data/spec/generators/rolify/role/role_generator_spec.rb +17 -61
- data/spec/rolify/custom_spec.rb +12 -0
- data/spec/rolify/resource_spec.rb +31 -0
- data/spec/rolify/role_spec.rb +12 -0
- data/spec/rolify/shared_contexts.rb +12 -0
- data/spec/rolify/shared_examples/shared_examples_for_callbacks.rb +57 -0
- data/spec/rolify/shared_examples/shared_examples_for_finders.rb +77 -0
- data/spec/rolify/shared_examples/shared_examples_for_roles.rb +39 -27
- data/spec/rolify/shared_examples/shared_examples_for_scopes.rb +38 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/support/adapters/active_record.rb +4 -0
- data/spec/support/adapters/mongoid.rb +23 -3
- data/spec/support/adapters/mongoid.yml +6 -0
- metadata +82 -30
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
= 3.2 (unreleased yet)
|
2
|
+
* <b>DEPRECATION NOTICE:</b>Ruby 1.8 support dropped ! Mongoid 3.0 only supports MRI 1.9.3, and HEAD, and JRuby 1.6.0+ in 1.9 mode
|
3
|
+
* removed <tt>dynamic_shortcuts</tt> arguments from the generator
|
4
|
+
* to use dynamic shortcuts feature when you're using ActiveRecord, you have to enable it _after_ running rake db:migrate as it relies on the roles table
|
5
|
+
* support for Mongoid 3.x (thanks to @Leonas)
|
6
|
+
* new class methods on the User class to find users depending on roles they have
|
7
|
+
* added scopes to Role class to be able to fetch global, class scoped and instance scoped roles for a specific user
|
8
|
+
* deletions of n-n relation are unreliable with Mongoid. Removing ids instead (thanks to @nfo)
|
9
|
+
* <tt>has_role?</tt> method now supports new instance (i.e. record not saved in the database yet) (thanks to @demental)
|
10
|
+
* added association callbacks <tt>(before|after)_add</tt>, <tt>(before|after)_remove</tt> on <tt>rolify</tt> method (thanks to @shekibobo)
|
11
|
+
* added ability to pass an array of roles to <tt>Resource.with_role()</tt>, aliased by <tt>Resource.with_roles()</tt> (thanks to @lukes)
|
12
|
+
* added option to have roles be destroyed by default if parent resource is destroyed (thanks to @treydock)
|
13
|
+
* better edge cases covering in the specs
|
14
|
+
* fixed a bug regarding the loading order of the railtie when using Mongoid ORM and other gems using initializer files (thanks to @stigi)
|
15
|
+
* fixed double quote syntax when using MySQL
|
16
|
+
* documentation improvement
|
17
|
+
|
1
18
|
= 3.1 (Apr 6, 2012)
|
2
19
|
* Mongoid adapter optimization
|
3
20
|
* adapter code refactoring
|
data/README.md
CHANGED
@@ -13,9 +13,10 @@ This library was intended to be used with [CanCan](https://github.com/ryanb/canc
|
|
13
13
|
|
14
14
|
## Requirements
|
15
15
|
|
16
|
-
* >=
|
17
|
-
* ActiveRecord
|
18
|
-
* supports ruby 1.
|
16
|
+
* Rails >= 3.1
|
17
|
+
* ActiveRecord >= 3.1 <b>or</b> Mongoid >= 3.0
|
18
|
+
* supports ruby 1.9, JRuby 1.6.0+ (in 1.9 mode) and Rubinius 2.0.0dev (in 1.9 mode)
|
19
|
+
* support of ruby 1.8 has been dropped due to Mongoid 3.0 that only supports 1.9 new hash syntax
|
19
20
|
|
20
21
|
## Installation
|
21
22
|
|
@@ -54,7 +55,41 @@ Let's migrate !
|
|
54
55
|
rake db:migrate
|
55
56
|
```
|
56
57
|
|
57
|
-
### 3.
|
58
|
+
### 3.1 Configure your user model
|
59
|
+
|
60
|
+
This gem adds the `rolify` method to your User class. You can also specify optional callbacks* on the user for when roles are added or removed:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
class User < ActiveRecord::Base
|
64
|
+
rolify :before_add => :before_add_method
|
65
|
+
|
66
|
+
def :before_add_method(role)
|
67
|
+
# do something before it gets added
|
68
|
+
end
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
The `rolify` method accepts the following callback* options:
|
73
|
+
|
74
|
+
- `before_add`
|
75
|
+
- `after_add`
|
76
|
+
- `before_remove`
|
77
|
+
- `after_remove`
|
78
|
+
|
79
|
+
*PLEASE NOTE: callbacks are currently only supported using ActiveRecord ORM. Mongoid will support association callbacks in its 3.1 release (Mongoid current version is 3.0.x)
|
80
|
+
|
81
|
+
### 3.2 Configure your resource models
|
82
|
+
|
83
|
+
In the resource models you want to apply roles on, just add ``resourcify`` method.
|
84
|
+
For example, on this ActiveRecord class:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
class Forum < ActiveRecord::Base
|
88
|
+
resourcify
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
### 4. Add a role to a user
|
58
93
|
|
59
94
|
To define a global role:
|
60
95
|
|
@@ -79,7 +114,7 @@ To define a role scoped to a resource class
|
|
79
114
|
|
80
115
|
That's it !
|
81
116
|
|
82
|
-
###
|
117
|
+
### 5. Role queries
|
83
118
|
|
84
119
|
To check if a user has a global role:
|
85
120
|
|
@@ -125,7 +160,7 @@ A global role overrides resource role request:
|
|
125
160
|
=> true
|
126
161
|
```
|
127
162
|
|
128
|
-
###
|
163
|
+
### 6. Resource roles querying
|
129
164
|
|
130
165
|
Starting from rolify 3.0, you can search roles on instance level or class level resources.
|
131
166
|
|
@@ -160,6 +195,7 @@ Starting from rolify 3.0, you can search roles on instance level or class level
|
|
160
195
|
* [Wiki](https://github.com/EppO/rolify/wiki)
|
161
196
|
* [Usage](https://github.com/EppO/rolify/wiki/Usage): all the available commands
|
162
197
|
* [Tutorial](https://github.com/EppO/rolify/wiki/Tutorial): how to use [rolify](http://eppo.github.com/rolify) with [Devise](https://github.com/plataformatec/devise) and [CanCan](https://github.com/ryanb/cancan).
|
198
|
+
* [Amazing tutorial](http://railsapps.github.com/tutorial-rails-bootstrap-devise-cancan.html) provided by [RailsApps](http://railsapps.github.com/)
|
163
199
|
|
164
200
|
## Questions or Problems?
|
165
201
|
|
@@ -9,14 +9,14 @@ module Rolify
|
|
9
9
|
argument :role_cname, :type => :string, :default => "Role"
|
10
10
|
argument :user_cname, :type => :string, :default => "User"
|
11
11
|
argument :orm_adapter, :type => :string, :default => "active_record"
|
12
|
-
class_option :dynamic_shortcuts, :type => :boolean, :default => false
|
12
|
+
#class_option :dynamic_shortcuts, :type => :boolean, :default => false
|
13
13
|
|
14
14
|
desc "Generates a model with the given NAME and a migration file."
|
15
15
|
|
16
16
|
def generate_role
|
17
17
|
template "role-#{orm_adapter}.rb", "app/models/#{role_cname.underscore}.rb"
|
18
|
-
|
19
|
-
"
|
18
|
+
inject_into_file(model_path, :after => inject_rolify_method) do
|
19
|
+
" rolify" + (role_cname == "Role" ? "" : " :role_cname => '#{role_cname.camelize}'") + "\n"
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -36,6 +36,14 @@ module Rolify
|
|
36
36
|
def show_readme
|
37
37
|
readme "README-#{orm_adapter}" if behavior == :invoke
|
38
38
|
end
|
39
|
+
|
40
|
+
def inject_rolify_method
|
41
|
+
if orm_adapter == "active_record"
|
42
|
+
/class #{user_cname.camelize}\n|class #{user_cname.camelize} .*\n/
|
43
|
+
else
|
44
|
+
/include Mongoid::Document\n|include Mongoid::Document .*\n/
|
45
|
+
end
|
46
|
+
end
|
39
47
|
end
|
40
48
|
end
|
41
49
|
end
|
@@ -3,5 +3,6 @@ Rolify.configure do |config|
|
|
3
3
|
<%= "# " if orm_adapter == "active_record" %>config.use_mongoid
|
4
4
|
|
5
5
|
# Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false
|
6
|
-
|
6
|
+
# Enable this feature _after_ running rake db:migrate as it relies on the roles table
|
7
|
+
# config.use_dynamic_shortcuts
|
7
8
|
end
|
@@ -5,13 +5,15 @@ class <%= role_cname.camelize %>
|
|
5
5
|
belongs_to :resource, :polymorphic => true
|
6
6
|
|
7
7
|
field :name, :type => String
|
8
|
-
index :name, unique
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
)
|
8
|
+
index({ :name => 1 }, { :unique => true })
|
9
|
+
|
10
|
+
|
11
|
+
index({
|
12
|
+
:name => 1,
|
13
|
+
:resource_type => 1,
|
14
|
+
:resource_id => 1
|
15
|
+
},
|
16
|
+
{ :unique => true})
|
17
|
+
|
18
|
+
scopify
|
17
19
|
end
|
data/lib/rolify.rb
CHANGED
@@ -11,12 +11,16 @@ module Rolify
|
|
11
11
|
|
12
12
|
attr_accessor :role_cname, :adapter
|
13
13
|
|
14
|
-
def rolify(options = {
|
14
|
+
def rolify(options = {})
|
15
15
|
include Role
|
16
16
|
extend Dynamic if Rolify.dynamic_shortcuts
|
17
17
|
|
18
|
+
options.reverse_merge!({:role_cname => 'Role'})
|
19
|
+
|
18
20
|
rolify_options = { :class_name => options[:role_cname].camelize }
|
19
21
|
rolify_options.merge!({ :join_table => "#{self.to_s.tableize}_#{options[:role_cname].tableize}" }) if Rolify.orm == "active_record"
|
22
|
+
rolify_options.merge!(options.select{ |k,v| [:before_add, :after_add, :before_remove, :after_remove].include? k.to_sym }) if Rolify.orm == "active_record"
|
23
|
+
|
20
24
|
has_and_belongs_to_many :roles, rolify_options
|
21
25
|
|
22
26
|
self.adapter = Rolify::Adapter::Base.create("role_adapter", options[:role_cname], self.name)
|
@@ -25,18 +29,22 @@ module Rolify
|
|
25
29
|
load_dynamic_methods if Rolify.dynamic_shortcuts
|
26
30
|
end
|
27
31
|
|
28
|
-
def resourcify(options = { :role_cname => 'Role' })
|
32
|
+
def resourcify(options = { :role_cname => 'Role', :dependent => :destroy })
|
29
33
|
include Resource
|
30
34
|
|
31
|
-
resourcify_options = { :class_name => options[:role_cname].camelize }
|
32
|
-
resourcify_options.merge!({ :as => :resource })
|
35
|
+
resourcify_options = { :class_name => options[:role_cname].camelize, :as => :resource, :dependent => options[:dependent] }
|
33
36
|
has_many :roles, resourcify_options
|
34
37
|
|
35
38
|
self.adapter = Rolify::Adapter::Base.create("resource_adapter", options[:role_cname], self.name)
|
36
39
|
self.role_cname = options[:role_cname]
|
37
40
|
end
|
38
41
|
|
42
|
+
def scopify
|
43
|
+
require "rolify/adapters/#{Rolify.orm}/scopes.rb"
|
44
|
+
extend Rolify::Adapter::Scopes
|
45
|
+
end
|
46
|
+
|
39
47
|
def role_class
|
40
48
|
self.role_cname.constantize
|
41
49
|
end
|
42
|
-
end
|
50
|
+
end
|
@@ -4,13 +4,20 @@ module Rolify
|
|
4
4
|
module Adapter
|
5
5
|
class ResourceAdapter < ResourceAdapterBase
|
6
6
|
def resources_find(roles_table, relation, role_name)
|
7
|
-
resources = relation.joins("INNER JOIN
|
8
|
-
resources = resources.where("#{roles_table}.name
|
7
|
+
resources = relation.joins("INNER JOIN #{quote(roles_table)} ON #{quote(roles_table)}.resource_type = '#{relation.to_s}'")
|
8
|
+
resources = resources.where("#{quote(roles_table)}.name IN (?) AND #{quote(roles_table)}.resource_type = ?", Array(role_name), relation.to_s)
|
9
9
|
resources
|
10
10
|
end
|
11
11
|
|
12
|
-
def in(relation,
|
13
|
-
|
12
|
+
def in(relation, user, role_names)
|
13
|
+
roles = user.roles.where(:name => role_names)
|
14
|
+
relation.where("#{quote(role_class.to_s.tableize)}.id IN (?) AND ((resource_id = #{quote(relation.table_name)}.id) OR (resource_id IS NULL))", roles)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def quote(column)
|
20
|
+
ActiveRecord::Base.connection.quote_column_name column
|
14
21
|
end
|
15
22
|
end
|
16
23
|
end
|
@@ -32,6 +32,13 @@ module Rolify
|
|
32
32
|
def exists?(relation, column)
|
33
33
|
relation.where("#{column} IS NOT NULL")
|
34
34
|
end
|
35
|
+
|
36
|
+
def scope(relation, conditions)
|
37
|
+
query = relation.scoped
|
38
|
+
query = query.joins(:roles)
|
39
|
+
query = where(query, conditions)
|
40
|
+
query
|
41
|
+
end
|
35
42
|
|
36
43
|
private
|
37
44
|
|
@@ -54,15 +61,15 @@ module Rolify
|
|
54
61
|
end
|
55
62
|
|
56
63
|
def build_query(role, resource = nil)
|
57
|
-
return [ "name = ?", [ role ] ] if resource == :any
|
58
|
-
query = "((name = ?) AND (resource_type IS NULL) AND (resource_id IS NULL))"
|
64
|
+
return [ "#{role_table}.name = ?", [ role ] ] if resource == :any
|
65
|
+
query = "((#{role_table}.name = ?) AND (#{role_table}.resource_type IS NULL) AND (#{role_table}.resource_id IS NULL))"
|
59
66
|
values = [ role ]
|
60
67
|
if resource
|
61
68
|
query.insert(0, "(")
|
62
|
-
query += " OR ((name = ?) AND (resource_type = ?) AND (resource_id IS NULL))"
|
69
|
+
query += " OR ((#{role_table}.name = ?) AND (#{role_table}.resource_type = ?) AND (#{role_table}.resource_id IS NULL))"
|
63
70
|
values << role << (resource.is_a?(Class) ? resource.to_s : resource.class.name)
|
64
71
|
if !resource.is_a? Class
|
65
|
-
query += " OR ((name = ?) AND (resource_type = ?) AND (resource_id = ?))"
|
72
|
+
query += " OR ((#{role_table}.name = ?) AND (#{role_table}.resource_type = ?) AND (#{role_table}.resource_id = ?))"
|
66
73
|
values << role << resource.class.name << resource.id
|
67
74
|
end
|
68
75
|
query += ")"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rolify
|
2
|
+
module Adapter
|
3
|
+
module Scopes
|
4
|
+
def global
|
5
|
+
where(:resource_type => nil, :resource_id => nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
def class_scoped(resource_type = nil)
|
9
|
+
where_conditions = "resource_type IS NOT NULL AND resource_id IS NULL"
|
10
|
+
where_conditions = [ "resource_type = ? AND resource_id IS NULL", resource_type.name ] if resource_type
|
11
|
+
where(where_conditions)
|
12
|
+
end
|
13
|
+
|
14
|
+
def instance_scoped(resource_type = nil)
|
15
|
+
where_conditions = "resource_type IS NOT NULL AND resource_id IS NOT NULL"
|
16
|
+
if resource_type
|
17
|
+
if resource_type.is_a? Class
|
18
|
+
where_conditions = [ "resource_type = ? AND resource_id IS NOT NULL", resource_type.name ]
|
19
|
+
else
|
20
|
+
where_conditions = [ "resource_type = ? AND resource_id = ?", resource_type.class.name, resource_type.id ]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
where(where_conditions)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/rolify/adapters/base.rb
CHANGED
@@ -14,8 +14,13 @@ module Rolify
|
|
14
14
|
@user_cname.constantize
|
15
15
|
end
|
16
16
|
|
17
|
+
def role_table
|
18
|
+
@role_cname.tableize
|
19
|
+
end
|
20
|
+
|
17
21
|
def self.create(adapter, role_cname, user_cname)
|
18
22
|
load "rolify/adapters/#{Rolify.orm}/#{adapter}.rb"
|
23
|
+
load "rolify/adapters/#{Rolify.orm}/scopes.rb"
|
19
24
|
Rolify::Adapter.const_get(adapter.camelize.to_sym).new(role_cname, user_cname)
|
20
25
|
end
|
21
26
|
end
|
@@ -4,16 +4,20 @@ module Rolify
|
|
4
4
|
module Adapter
|
5
5
|
class ResourceAdapter < ResourceAdapterBase
|
6
6
|
def resources_find(roles_table, relation, role_name)
|
7
|
-
roles = roles_table.classify.constantize.where(:name => role_name, :resource_type => relation.to_s)
|
7
|
+
roles = roles_table.classify.constantize.where(:name.in => Array(role_name), :resource_type => relation.to_s)
|
8
8
|
resources = []
|
9
9
|
roles.each do |role|
|
10
|
-
|
11
|
-
|
10
|
+
if role.resource_id.nil?
|
11
|
+
resources += relation.all
|
12
|
+
else
|
13
|
+
resources << role.resource
|
14
|
+
end
|
12
15
|
end
|
13
|
-
resources
|
16
|
+
resources.uniq
|
14
17
|
end
|
15
18
|
|
16
|
-
def in(resources,
|
19
|
+
def in(resources, user, role_names)
|
20
|
+
roles = user.roles.where(:name.in => Array(role_names))
|
17
21
|
return [] if resources.empty? || roles.empty?
|
18
22
|
resources.delete_if { |resource| (resource.applied_roles & roles).empty? }
|
19
23
|
resources
|
@@ -24,8 +24,13 @@ module Rolify
|
|
24
24
|
roles.merge!({ :resource_id => resource.id }) if resource && !resource.is_a?(Class)
|
25
25
|
roles_to_remove = relation.roles.where(roles)
|
26
26
|
roles_to_remove.each do |role|
|
27
|
-
|
28
|
-
role
|
27
|
+
# Deletion in n-n relations is unreliable. Sometimes it works, sometimes not.
|
28
|
+
# So, this does not work all the time: `relation.roles.delete(role)`
|
29
|
+
# @see http://stackoverflow.com/questions/9132596/rails3-mongoid-many-to-many-relation-and-delete-operation
|
30
|
+
# We instead remove ids from the Role object and the relation object.
|
31
|
+
relation.role_ids.delete(role.id)
|
32
|
+
role.send((user_class.to_s.underscore + '_ids').to_sym).delete(relation.id)
|
33
|
+
|
29
34
|
role.destroy if role.send(user_class.to_s.tableize.to_sym).empty?
|
30
35
|
end
|
31
36
|
end
|
@@ -33,6 +38,13 @@ module Rolify
|
|
33
38
|
def exists?(relation, column)
|
34
39
|
relation.where(column.to_sym.ne => nil)
|
35
40
|
end
|
41
|
+
|
42
|
+
def scope(relation, conditions)
|
43
|
+
roles = where(role_class, conditions).map { |role| role.id }
|
44
|
+
return [] if roles.size.zero?
|
45
|
+
query = relation.any_in(:role_ids => roles)
|
46
|
+
query
|
47
|
+
end
|
36
48
|
|
37
49
|
private
|
38
50
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rolify
|
2
|
+
module Adapter
|
3
|
+
module Scopes
|
4
|
+
def global
|
5
|
+
where(:resource_type => nil, :resource_id => nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
def class_scoped(resource_type = nil)
|
9
|
+
where_conditions = { :resource_type.ne => nil, :resource_id => nil }
|
10
|
+
where_conditions = { :resource_type => resource_type.name, :resource_id => nil } if resource_type
|
11
|
+
where(where_conditions)
|
12
|
+
end
|
13
|
+
|
14
|
+
def instance_scoped(resource_type = nil)
|
15
|
+
where_conditions = { :resource_type.ne => nil, :resource_id.ne => nil }
|
16
|
+
if resource_type
|
17
|
+
if resource_type.is_a? Class
|
18
|
+
where_conditions = { :resource_type => resource_type.name, :resource_id.ne => nil }
|
19
|
+
else
|
20
|
+
where_conditions = { :resource_type => resource_type.class.name, :resource_id => resource_type.id }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
where(where_conditions)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Rolify
|
2
|
+
module Finders
|
3
|
+
def with_role(role_name, resource = nil)
|
4
|
+
self.adapter.scope(self, :name => role_name, :resource => resource)
|
5
|
+
end
|
6
|
+
|
7
|
+
def with_all_roles(*args)
|
8
|
+
users = []
|
9
|
+
args.each do |arg|
|
10
|
+
if arg.is_a? Hash
|
11
|
+
users_to_add = self.with_role(arg[:name], arg[:resource])
|
12
|
+
elsif arg.is_a?(String) || arg.is_a?(Symbol)
|
13
|
+
users_to_add = self.with_role(arg)
|
14
|
+
else
|
15
|
+
raise ArgumentError, "Invalid argument type: only hash or string or symbol allowed"
|
16
|
+
end
|
17
|
+
users = users_to_add if users.empty?
|
18
|
+
users &= users_to_add
|
19
|
+
return [] if users.empty?
|
20
|
+
end
|
21
|
+
users
|
22
|
+
end
|
23
|
+
|
24
|
+
def with_any_role(*args)
|
25
|
+
users = []
|
26
|
+
args.each do |arg|
|
27
|
+
if arg.is_a? Hash
|
28
|
+
users_to_add = self.with_role(arg[:name], arg[:resource])
|
29
|
+
elsif arg.is_a?(String) || arg.is_a?(Symbol)
|
30
|
+
users_to_add = self.with_role(arg)
|
31
|
+
else
|
32
|
+
raise ArgumentError, "Invalid argument type: only hash or string or symbol allowed"
|
33
|
+
end
|
34
|
+
users += users_to_add
|
35
|
+
end
|
36
|
+
users.uniq
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|