= Aegis - role-based permissions for your user models Aegis allows you to manage fine-grained, complex permission for user accounts in a central place. == Installation Add the following to your Initializer.run block in your environment.rb: config.gem 'makandra-aegis', :lib => 'aegis', :source => 'http://gems.github.com' Then do a sudo rake gems:install Alternatively, use sudo gem sources -a http://gems.github.com sudo gem install makandra-aegis == Example First, let's define some roles: # app/models/permissions.rb class Permissions < Aegis::Permissions role :guest role :registered_user role :moderator role :administrator, :default_permission => :allow permission :edit_post do |user, post| allow :registered_user do post.creator == user # a registered_user can only edit his own posts end allow :moderator end permission :read_post do |post| allow :everyone deny :guest do post.private? # guests may not read private posts end end end Now we assign roles to users. For this, the users table needs to have a string column +role_name+. # app/models/user.rb class User has_role end These permissions may be used in views and controllers: # app/views/posts/index.html.erb @posts.each do |post| <% if current_user.may_read_post? post %> <%= render post %> <% if current_user.may_edit_post? post %> <%= link_to 'Edit', edit_post_path(post) %> <% end %> <% end %> <% end %> # app/controllers/posts_controller.rb class PostsController # ... def update @post = Post.find(params[:id]) current_user.may_edit_post! @post # raises an Aegis::PermissionError for unauthorized access # ... end end == Details === Roles To equip a (user) model with any permissions, you simply call *has_role* within the model: class User < ActiveRecord::Base has_role end Aegis assumes that the corresponding database table has a string-valued column called +role_name+. You may override the name with the :name_accessor => :my_role_column option. The roles and permissions themselves are defined in a class inheriting from Aegis::Permissions. To define roles you create a model permissions.rb and use the *role* method: class Permissions < Aegis::Permissions role 'role_name' end By default, users belonging to this role are not permitted anything. You may override this with :default_permission => :allow, e.g. role 'admin', :default_permission => :allow === Permissions Permissions are specified with the *permission* method and *allow* and *deny* permission :do_something do allow :role_a, :role_b deny :role_c end Your user model just received two methods called User#may_do_something? and User#may_do_something!. The first one with the ? returns true for users with +role_a+ and +role_b+, and false for users with +role_c+. The second one with the ! raises an Aegis::PermissionError for +role_c+. === Normalization Aegis will perform some normalization. For example, the permissions +edit_something+ and +update_something+ will be the same, each granting both may_edit_something? and may_update_something?. The following normalizations are active: * edit = update * show = list = view = read * delete = remove = destroy === Complex permissions (with parameters) *allow* and *deny* can also take a block that may return +true+ or +false+ indicating if this really applies. So permission :pull_april_fools_prank do allow :everyone do Date.today.month == 4 and Date.today.day == 1 end end will generate a may_pull_april_fools_prank? method that only returns true on April 1. This becomes more useful if you pass parameters to a may_...? method, which are passed through to the permission block (together with the user object). This way you can define more complex permissions like permission :edit_post do |current_user, post| allow :registered_user do post.owner == current_user end allow :admin end which will permit admins and post owners to edit posts. === For your convenience As a convenience, if you create a permission ending in a plural 's', this automatically includes the singular form. That is, after permission :read_posts do allow :everyone end .may_read_post? @post will return true, as well. If you want to grant +create_something+, +read_something+, +update_something+ and +destroy_something+ permissions all at once, just use permission :crud_something do allow :admin end If several permission blocks (or several allow and denies) apply to a certain role, the later one always wins. That is permission :do_something do deny :everyone allow :admin end will work as expected.