Class: Trust::Permissions
- Inherits:
-
Object
- Object
- Trust::Permissions
- Includes:
- InheritableAttribute
- Defined in:
- lib/trust/permissions.rb
Overview
Trust Permissions
Permissions should be specified in a separate file in you app/model directory. The file could look like this:
module Permissions
class Default < Trust::Permissions
...
end
...
end
The above is the minimum required definitions that must exist in you file. Default
will be used if no classes match the permissions requested, so the Default
class definition is mandatory.
If you want to separate the permissions into separate files that is ok. Then you shoud place these files in the /app/model/permissions directory.
Defining permisions
The basic rules is to define classes in the Permissions module that matches your models. Here are some examples:
-
Project
should have a matching classPermissions::Project
-
Account
should have a matching classPermissions::Account
-
Account:Credit
may have a matching classPermissions::Account::Credit
, but if its inheriting fromAccount
and no special handling is necessary, it is not necessary to create the permissions class.
Using inheritance
Inheritance is also fully supported, but should generally follow your own inheritance model
module Permissions
class Account < Default
role :admin, :accountant do
...
end
end
class Account::Credit < Account
...
end
end
Action aliases
You can define aliases for actions. You do this by setting the action_aliases
attribute on Trust::Permissions class Example:
Trust::Permissions.action_aliases = {
read: [:index, :show],
create: [:create, :new]
}
Keep in mind that all permissions are expanded upon declaration, so when using the can?
method you must refer to the actual action and not the alias. The alias will never give a positive permission.
Accessors
Accessors that can be used when testing permissions:
-
user
- the user currently logged in -
action
- the action request from the controller such as :edit, or the action tested from helper or from the object itself when usingActiveRecord::can?
is being used. -
subject
- the object that is being tested for permissions. This may be a an existing object, a new object (such as for:create
and:new
action), or nil if no object has been instantiated. -
parent
- the parent object if in a nested route, specified bybelongs_to
in the controller. -
klass
- the class of involed in the request. It can be a base class or the real class, depending on your controller design.
Defining your own accessors or instance methods
You can easily define your own accessors in the classes. These can be helpful when declaring permissions.
Example:
class Account < Trust::Permissions
role :admin, :accountant do
can :update, :unless => :closed?
end
def closed?
subject.closed?
end
end
In the above example closed is testing on the subject to see if it is closed. The permission is referring to this method when evaluated. Keep in mind that you must refer to the subject
, as you do not access the inctance of the object directly.
Constant Summary collapse
- @@can_expressions =
0
Instance Attribute Summary collapse
-
#action ⇒ Object
readonly
Returns the value of attribute action.
-
#klass ⇒ Object
readonly
Returns the value of attribute klass.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#subject ⇒ Object
readonly
Returns the value of attribute subject.
-
#user ⇒ Object
readonly
Returns the value of attribute user.
Class Method Summary collapse
-
.can(*args) ⇒ Object
Defines permissions.
-
.cannot(*args) ⇒ Object
Revokes permissions.
-
.role(*roles, &block) ⇒ Object
(also: roles)
Assign permissions to one or more roles.
Instance Method Summary collapse
-
#authorized? ⇒ Boolean
Returns true if the user is authorized to perform the action.
-
#initialize(user, action, klass, subject, parent) ⇒ Permissions
constructor
Initializes the permission object.
Methods included from InheritableAttribute
Constructor Details
#initialize(user, action, klass, subject, parent) ⇒ Permissions
Initializes the permission object
calling the authorized?
method on the instance later will test for the authorization.
Parameters:
+user+ - user object, must respond to role_symbols
+action+ - action, such as :create, :show, etc. Should not be an alias
+klass+ - the class of the subject.
+subject+ - the subject tested for authorization
+parent+ - the parent object, normally declared through belongs_to
See Authorization for more details
139 140 141 |
# File 'lib/trust/permissions.rb', line 139 def initialize(user, action, klass, subject, parent) @user, @action, @klass, @subject, @parent = user, action, klass, subject, parent end |
Instance Attribute Details
#action ⇒ Object (readonly)
Returns the value of attribute action.
113 114 115 |
# File 'lib/trust/permissions.rb', line 113 def action @action end |
#klass ⇒ Object (readonly)
Returns the value of attribute klass.
113 114 115 |
# File 'lib/trust/permissions.rb', line 113 def klass @klass end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
113 114 115 |
# File 'lib/trust/permissions.rb', line 113 def parent @parent end |
#subject ⇒ Object (readonly)
Returns the value of attribute subject.
113 114 115 |
# File 'lib/trust/permissions.rb', line 113 def subject @subject end |
#user ⇒ Object (readonly)
Returns the value of attribute user.
113 114 115 |
# File 'lib/trust/permissions.rb', line 113 def user @user end |
Class Method Details
.can(*args) ⇒ Object
Defines permissions
Arguments
action - can be an alias or an actions of some kind
options - control the behavior of the permission
Options
+:if/:unless+ - :symbol or proc that will be called to evaluate an expression
+enforce+ - set to true to enforce the permission, delete any previous grants given from parent classes. Most meaningful in
combination with +:if+ and +:unless+ options
Example
module Permissions
class Account < Trust::Permissions
role :admin, :accountant do
can :read
can :update, :unless => :closed?
end
end
end
The above permits admin and accountant to read accounts, but can update only if the account is not closed. In the example above a method is used to test data on the actual record when testing for permissions.
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/trust/permissions.rb', line 269 def can(*args) = args. enforce = .delete(:enforce) p = (args).collect { |action| [action, ] } if @in_role_block @perms[:can] += p if enforce @perms[:cannot] = (args).collect { |action| action } end else @@can_expressions += 1 perms = {:can => p } if enforce perms[:cannot] = (args).collect { |action| action } end return perms end end |
.cannot(*args) ⇒ Object
Revokes permissions.
Revokes any previous permissions given in parent classes. This cannot be used with conditions. See also :enforce
option for can
can
has presedence over cannot
. In practice this means that in a block; cannot
statements are processed before can
, and any previously permissions granted are deleted. Another way to say this is; if you have cannot :destroy and can :destroy, then all inheritied destroys will first be deleted, and then the can destroy will be granted.
Arguments
action - actions to be revoked permissions for. Cannot be aliases
Example
module Permissions
class Account < Trust::Permissions
role :admin, :accountant do
can :read
can :read
can :update, :destroy, :unless => :closed?
end
end
class Account::Credit < Account
role :accountant do
cannot :destroy # revoke permission to destroy
end
end
end
321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/trust/permissions.rb', line 321 def cannot(*args) = args. raise ArgumentError, "No options (#{.inspect}) are allowed for cannot. It is just meaning less" if .size > 0 p = (args).collect { |action| action } if @in_role_block @perms[:cannot] += p else @@can_expressions += 1 return {:cannot => p } end end |
.role(*roles, &block) ⇒ Object Also known as: roles
Assign permissions to one or more roles.
You may call role or roles, they are the same function like role :admin or roles :admin, :accountant
There are two ways to call role, with or without block. If you want to set multiple permissions with different conditons then you should use a block.
module Permissions
class Account < Trust::Permissions
role :admin, can(:manage, :audit)
end
end
The above assigns the manage and audit permissions to admin.
module Permissions
class Account < Trust::Permissions
role :admin, :accountant do
can :read
can :update
end
end
end
The above permits admin and accountant to read accounts.
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/trust/permissions.rb', line 208 def role(*roles, &block) if block_given? if @@can_expressions > 0 @@can_expressions = 0 raise RoleAssigmnentMissing end @perms = {:can => [], :cannot => []} @in_role_block = true yield @in_role_block = false perms = @perms else if @@can_expressions > 1 @@can_expressions = 0 raise RoleAssigmnentMissing end perms = roles. unless perms.size >= 1 && (perms[:can] || perms[:cannot]) raise ArgumentError, "Must have a block or a can or a cannot expression: #{perms.inspect}" end @@can_expressions = 0 end roles.flatten.each do |role| self.[role] ||= [] if perms[:cannot] && perms[:cannot].size > 0 perms[:cannot].each do |p| self.[role].delete_if { |perm| perm[0] == p } end end if perms[:can] && perms[:can].size > 0 self.[role] += perms[:can] end end end |
Instance Method Details
#authorized? ⇒ Boolean
Returns true if the user is authorized to perform the action
144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/trust/permissions.rb', line 144 def = nil user && user.role_symbols.each do |role| ([role] || {}).each do |act, opt| if act == action break if ( = opt.any? ? eval_expr(opt) : true) end end break if end end |