Home > master-may-i

master-may-i

Master-may-i is a project mainly written in RUBY and JAVASCRIPT, based on the MIT license.

Super simple model based authorization designed to work with AuthLogic

= Master May I?

=== Clean, simple and flexible model based authorization designed to work with AuthLogic and InheritedResources.

=== If these docs looks all wanky, then be sure you're viewing them on the rdoc.info site: http://rdoc.info/projects/tsaleh/master-may-i

== Overview

{MasterMayI Master May I} is not an Access Control List system. In fact, it has absolutely no opinions about how you structure your underlying business rules. All it does is gives you a consistent and flexible pattern for accessing those rules.

There are two main components:

=== The Model Layer

{MasterMayI Master May I} adds query methods to all your models, which can be used to determine who's allowed to do what. {MasterMayI::ActiveRecordExtensions Learn more.}

  • {MasterMayI::ActiveRecordExtensions::ClassMethods#creatable_by? +Model.creatable_by?(user)+} and {MasterMayI::ActiveRecordExtensions::ClassMethods#creatable? +Model.creatable?+}
  • {MasterMayI::ActiveRecordExtensions::InstanceMethods#readable_by? [email protected]_by?(user)+} and {MasterMayI::ActiveRecordExtensions::InstanceMethods#readable? [email protected]?+}
  • {MasterMayI::ActiveRecordExtensions::InstanceMethods#editable_by? [email protected]_by?(user)+} and {MasterMayI::ActiveRecordExtensions::InstanceMethods#editable? [email protected]?+}
  • {MasterMayI::ActiveRecordExtensions::InstanceMethods#destroyable_by? [email protected]_by?(user)+} and {MasterMayI::ActiveRecordExtensions::InstanceMethods#destroyable? [email protected]?+}

These are just methods (that default to always returning true), so customizing the rules is as easy as overriding the methods:

class Note < ActiveRecord::Base def self.creatable_by?(user) user and user.administrator? end end

{MasterMayI Master May I} also adds the {MasterMayI::ActiveRecordExtensions::ClassMethods#listable_by +Model.listable_by(user)+} and {MasterMayI::ActiveRecordExtensions::ClassMethods#listable +Model.listable+} methods, which return a named scope limiting the returned records to those viewable by the given user. Again, by default, it returns all records, and this should be redefined by each individual model.

If you call {MasterMayI::ActiveRecordExtensions::ClassMethods#records_creating_user +records_creating_user+} in your model, then the user from the Authlogic UserSession is automatically stored whenever a record is created. {MasterMayI::ActiveRecordExtensions::ClassMethods#records_creating_user Learn more.}

class Note < ActiveRecord::Base records_creating_user

def self.creatable_by?(user)
  user and created_by?(user)
end

end

=== The Controller Layer

If you include {MasterMayI::ControllerExtensions} in your ApplicationController, MasterMayI adds a few utility methods to your ApplicationController:

  • {MasterMayI::ControllerExtensions#current_user +current_user+}
  • {MasterMayI::ControllerExtensions#logged_in? +logged_in?+}
  • {MasterMayI::ControllerExtensions#require_user +require_user+}
  • {MasterMayI::ControllerExtensions#deny_access +deny_access+}
  • {MasterMayI::ControllerExtensions#store_location +store_location+}
  • {MasterMayI::ControllerExtensions#redirect_back_or +redirect_back_or url+}

{MasterMayI Master May I} will also include the {MasterMayI::ControllerExtensions::ClassMethods#protects_restful_actions +protects_restful_actions+} controller class method, which integrates with InheritedResources in order to automatically check with the model in a set of before filters. In addition, it will override the InheritedResources#collection method to filter by the listable scope. {MasterMayI::ControllerExtensions::ClassMethods#protects_restful_actions Learn more.}

class ApplicationController < ActionController::Base include MasterMayI::ControllerExtensions ... end

class NotesController < InheritedResources::Base protects_restful_actions end

{MasterMayI::ControllerExtensions Learn more.}

== Testing with Shoulda

{MasterMayI Master May I} comes with a strong set of Shoulda macros:

...for your {ActiveSupport::TestCase unit tests}:

class NoteTest < ActiveSupport::TestCase setup :activate_authlogic

should_record_creating_user :as => "user"

should_be_creatable_by("boy named sue-create") { Factory(:user, :username => "sue-create")  }
should_not_be_creatable_by("everyone")         { nil }

context "a note" do
  setup { @note = Factory(:note) }
  subject { @note }

  should_be_readable_by("boy named sue-read")       { Factory(:user, :username => "sue-read")    }
  should_be_editable_by("boy named sue-edit")       { Factory(:user, :username => "sue-edit")    }
  should_be_destroyable_by("boy named sue-destroy") { Factory(:user, :username => "sue-destroy") }

  should_not_be_readable_by(   "everyone") { nil }
  should_not_be_editable_by(   "everyone") { nil }
  should_not_be_destroyable_by("everyone") { nil }
end

end

...and your {ActionController::TestCase functional tests}:

class NotesControllerTest < ActionController::TestCase setup :activate_authlogic

as_a_logged_in_user do
  who_can_manage :notes do
    context "on GET to /notes/new" do
      setup { get :new }
      should_not_set_the_flash
      should_render_template :new
    end
    ...

== Installation

{MasterMayI Master May I} is hosted on gemcutter, so installation is as easy as:

sudo gem install master_may_i

It relies heavily on Authlogic, and the controller module uses the +resource+ and +resource_class+ methods from InheritedResources. Finally, the before filters expect there to be the a url helper named login_url:

map.login "/login", :controller => :user_session, :action => :new

== Copyright

Copyright (c) 2009 Tammer Saleh. See LICENSE for details.