Module ModelSecurity
In: lib/model_security.rb

The ModelSecurity module allows you to specify security permissions on any or all of the attributes of a model implemented using ActiveRecord.

Security permissions are specified in the declaration of the model’s class, similarly to the way you can specify validators. The specification includes the names of attributes to which permissions apply, and an optional permission test that should return true or false depending on whether the access should be allowed or denied.

 let_read :attribute|:all [[, :attribute ] ...], [:if => :test-name] [do block end]
 let_write :attribute|:all [[, :attribute ] ...], [:if => :test-name] [do block end]
 let_access :attribute|:all [[, :attribute ] ...], [:if => :test-name] [do block end]

let_read specifies when the attribute can be read, let_write specifies when it can be written, and let_access does both.

If no permission test is specified, that is the same as specifying a test that always returns true. Two stub tests are provided:

 :always?

Always returns true.

 :never?

Always returns false.

You can easily add your own tests as instance methods of your model:

 let_read :phone_number :if => :admin?

 def admin?
   return $current_login.is_the_administrator
 end

If the permission test is specified using the syntax

 :if => :test-name

it will be run as a method of the model this way:

 self.send(:test-name)

If the permission test is specified as a block, using do and end, it will be called with the binding of the active record instance that is being accessed.

Permission tests can also be strings, and these are passed to eval().

The special attribute name :all means that a test will be applied to all attributes of the model. Any tests for :all are run first, then any tests for the specific attribute. Any test that returns true ends the run, further tests will not be evaluated.

If no security permissions are declared for an attribute or :all, that attribute may always be accessed. Once a test for :all is delcared, that test will apply to all attributes of the model.

The security tests themselves may access any data with impunity. A global variable is used to disable further security testing while a security test is in progress.

Display Control

A companion mechanism is used to control views, including scaffold views, using a syntax similar to that for security specifications:

 let_display :attribute|:all [[, :attribute ] ...], [:if => :test-name] [do block end]

let_display is mostly useful for specifying if a table view should have a column for a particular attribute. Its tests must be declared as class methods of the model, while the tests of let_read, let_write, and let_access are instance methods. This is because the information declared by let_display is accessed before iteration over active records begins.

Accessing Security Test Results

ModelSecurity provides two instance methods, readable? and writable? to inform the program if a particular attribute can be accessed. The class method display? will return true or false depending upon whether a particular attribute should be displayed. These can be used to modify a view so that any non-writable data will not be presented in an editable field. ModelSecurityHelper overloads the methods that are usually used to edit models so that they will not attempt to read or write what they aren’t permitted and will render appropriately for the permissions on any model attribute. Those methods are: check_box, file_field, hidden_field, password_field, radio_button, text_area, text_field. ModelSecurityHelper also replaces the scaffold views with versions that never access data when not permitted to, render appropriately for the permissions on an attribute, and omit columns for which display? returns false.

Exceptions

ActiveRecord provides two internal methods that perform normal attribute accesses: read_attribute, and write_attribute. These are overloaded to perform security testing, and will raise SecurityError when an unpermitted access is attempted.

Methods

Included Modules

BothClassAndInstanceMethods

Classes and Modules

Module ModelSecurity::BothClassAndInstanceMethods
Module ModelSecurity::ClassMethods

Public Class methods

Ruby interpreter magic to cause the class methods herein to work correctly while a class including this module is still being declared.

Public Instance methods

Overloads ActiveRecord::Base#read_attribute. Read the attribute if that is permitted. Otherwise, throw an exception.

Return true if a read of attribute is permitted. attribute should be a symbol, and should be the name of a database field for this model.

This does the permission test for readable? or writable?.

Return true if a write of attribute is permitted. attribute should be a symbol, and should be the name of a database field for this model.

Overloads ActiveRecord::Base#write_attribute. Write the attribute if that is permitted. Otherwise, throw an exception.

[Validate]