<commit_before>=ActsAsAuthorizable

Acts As Authorizable is a solution for providing pseudo-hierarchical role based authorizations on ActiveRecord model instances using your existing database table relationships. It is designed to eliminate the need for deep nesting controllers due to authorization.

==Deep Nesting & Authorization

One reason why developers deeply nest controllers is to allow hierarchical permission. Hence you see the following...

  example.com/forums/forum_id/threads/thread_id/posts/post_id/edit
  
With deep nesting you can check a current user's permissions against the post,thread, and forum. So a moderator for a specific form instance would be able to modify a post using the permissions present on the forum instance. Yet this is no longer possible with...

  example.com/posts/post_id/edit
  
This is due to the fact that we don't have explicit information about where the post falls in an authorization hierarchy. This is where ActsAsAuthorizable provides an improvement. With the plugin you can specify where to go to get further authorization information on a post. So the forum moderator could access the page, even though he doesn't have direct permissions on the post.  

==Installation

  script/plugin install git://github.com/mleventi/acts_as_authorizable.git

==Usage

Acts As Authorizable works within your models by piggybacking on your has_many, has_one, and belongs_to associations to create a graph of model instances that represents authorization inheritance routes. For each ActiveRecord class you define which associations could yield permissions on the current class.

===Prerequisites

You need a model which most likely would be a Role. It has to have an instance method "allows?" that takes in a permission object and returns a boolean. Two examples below are fine...

  #Ex1
  class Role < ActiveRecord::Base
    def allows?(permission)
      #do something and return true or false
    end
  end
  
  #Ex2
  class Moo < ActiveRecord::Base
    def allows?(permission)
      #do something and return true or false
    end
  end
  
The permission parameter is a black box. It can be anything because ActsAsAuthorizable doesn't use it, just passes it around. You also need a ActiveRecord model that represents a user. 

===Example

  #ForumMembership, holds how the user is related to a forum
  class ForumMemberships < ActiveRecord::Base
    acts_as_authorizable
    
    belongs_to :user
    belongs_to :forum
    belongs_to :role
    
    named_scope :with_user, lambda { |user| {:conditions => {:user_id => user}}}
    
    auth_belongs_to_user :user, :role_association => :role
  end 
  
  #Forum
  class Forum < ActiveRecord::Base
    acts_as_authorizable
    
    has_many :forum_memberships
    has_many :threads
    
    auth_has_many_parents :forum_memberships, :user_scope => :with_user
  end
  
  #Thread
  class Forum < ActiveRecord::Base
    acts_as_authorizable
    
    belongs_to :forum
    has_many :posts
    
    auth_belongs_to_parent :forum
  end
  
  #Post
  class Post < ActiveRecord::Base
    acts_as_authorizable
    
    belongs_to :forum
    belongs_to :user
    
    auth_belongs_to_user :user, :role => Role.find_by_name('Post Owner')
    auth_belongs_to_parent :thread
  end
  
So the following models represent an authorization hierarchy. The ForumMembership model should allow authorizations for the particular Forum, Thread, & Post. Also the user association on a post, should allow some authorizations for that particular post.

Each of the four classes gets an injected authorized? instance method.
  
  model_instance.authorized?(user_instance,permission)
  
Now if you want to find out if a user has a permission on a certain post you simply call the post's authorized? method. This call uses the auth_* methods to load in additional models until the permission is found or we have looked through the associations.

Note: models are searched in depth first order, with the order within a model determined lexically by how auth_* are called. Hence you almost always want to have auth_belongs_to_user calls first. Then scoped auth_has_many_parents, auth_belongs_to_parent, and finallly not-scoped, auth_belongs_to_parent.

===Class Methods

====acts_as_authorized

This is included in ActiveRecord models that are part of the authorization graph. If you use any of the other class methods this needs to be included in your class definition.

====auth_belongs_to_user

This method takes several options...

- :association: What association to use to fetch the user instance, defaults to :user
- :role_association: What association defines the role for the corresponding user instance
- :role: What the user instance should be treated as assuming the :role_association option is not defined

====auth_belongs_to_parent

This method requires an association option

- :association


More Coming shortly...






Copyright (c) 2008 <NAME>, released under the MIT license<commit_msg>Better README with method examples and better description<commit_after>=ActsAsAuthorizable

Acts As Authorizable is a part solution for providing pseudo-hierarchical role based authorizations on ActiveRecord model instances using your existing database table relationships. It is designed to eliminate the need for deep nesting controllers due to authorization. That being said, it is only part of a total authorization mechanism. Essentially it takes an authorized? call and passes it to the appropriate Role.allows? methods. You still have to define filters in controllers that call ActiveRecord models authorized? method and write the allows? method in your role class.  

==Deep Nesting & Authorization

One reason why developers deeply nest controllers is to allow hierarchical permission. Hence you see the following...

  example.com/forums/forum_id/threads/thread_id/posts/post_id/edit
  
With deep nesting you can check a current user's permissions against the post,thread, and forum. So a moderator for a specific form instance would be able to modify a post using the permissions present on the forum instance. Yet this is no longer possible with...

  example.com/posts/post_id/edit
  
This is due to the fact that we don't have explicit information about where the post falls in an authorization hierarchy. This is where ActsAsAuthorizable provides an improvement. With the plugin you can specify where to go to get further authorization information on a post. So the forum moderator could access the page, even though he doesn't have direct permissions on the post.  

==Installation

  script/plugin install git://github.com/mleventi/acts_as_authorizable.git

Your going to need ActiveRecord 2.1 or greater.

==Usage

Acts As Authorizable works within your models by piggybacking on your has_many, has_one, and belongs_to associations to create a graph of model instances that represents authorization inheritance routes. For each ActiveRecord class you define which associations could yield permissions on the current class.

===Prerequisites

You need a model which most likely would be a Role. It has to have an instance method "allows?" that takes in a permission object and returns a boolean. Two examples below are fine...

  #Ex1
  class Role < ActiveRecord::Base
    def allows?(permission)
      #do something and return true or false
    end
  end
  
  #Ex2
  class Moo < ActiveRecord::Base
    def allows?(permission)
      #do something and return true or false
    end
  end
  
The permission parameter is a black box. It can be anything because ActsAsAuthorizable doesn't use it, just passes it around. You also need a ActiveRecord model that represents a user. 

===Example

  #ForumMembership, holds how the user is related to a forum
  class ForumMemberships < ActiveRecord::Base
    acts_as_authorizable
    
    belongs_to :user
    belongs_to :forum
    belongs_to :role
    
    named_scope :with_user, lambda { |user| {:conditions => {:user_id => user}}}
    
    auth_belongs_to_user :user, :role_association => :role
  end 
  
  #Forum
  class Forum < ActiveRecord::Base
    acts_as_authorizable
    
    has_many :forum_memberships
    has_many :threads
    
    auth_has_many_parents :forum_memberships, :user_scope => :with_user
  end
  
  #Thread
  class Forum < ActiveRecord::Base
    acts_as_authorizable
    
    belongs_to :forum
    has_many :posts
    
    auth_belongs_to_parent :forum
  end
  
  #Post
  class Post < ActiveRecord::Base
    acts_as_authorizable
    
    belongs_to :forum
    belongs_to :user
    
    auth_belongs_to_user :user, :role => 'Post Owner'
    auth_belongs_to_parent :thread
  end
  
So the following models represent an authorization hierarchy. The ForumMembership model should allow authorizations for the particular Forum, Thread, & Post. Also the user association on a post, should allow some authorizations for that particular post.

Each of the four classes gets an injected authorized? instance method.
  
  model_instance.authorized?(user_instance,permission)
  
Now if you want to find out if a user has a permission on a certain post you simply call the post's authorized? method. This call uses the auth_* methods to load in additional models until the permission is found or we have looked through the associations.

Note: models are searched in depth first order, with the order within a model determined lexically by how auth_* are called. Hence you almost always want to have auth_belongs_to_user calls first. Then scoped auth_has_many_parents, auth_belongs_to_parent, and finallly not-scoped, auth_belongs_to_parent.

===Class Methods

====acts_as_authorized

This is included in ActiveRecord models that are part of the authorization graph. If you use any of the other class methods this needs to be included in your class definition. It takes two optional parameters

- :role_class_name => A string representing the Role class name. Defaults to 'Role'
- :role_locate_method => A string representing a method on the Role class that is used to find roles. Defaults to 'find_by_name'.

Example:
  
  acts_as_authorized :role_class_name => 'Role', :role_locate_method => 'find_by_name'

====auth_belongs_to_user

This method takes several options...

- association REQUIRED, What association to use to fetch the user instance, defaults to :user
- :role_association => What association defines the role for the corresponding user instance
- :role => What the user instance should be treated as assuming the :role_association option is not defined. Passed as a parameter to the role_locate_method.

Example:
  
  #Association
  belongs_to :user
  #Auth Piggyback using a set role
  auth_belongs_to_user, :user, :role => 'Grand Poo Bah'
  
Or:

  #Association
  belongs_to :user
  belongs_to :role
  #Auth Piggyback using an associated role
  auth_belongs_to_user, :user, :role_association => :role
  

====auth_belongs_to_parent & auth_has_one_parent

- association REQUIRED, What association to follow.

Example:
  
  #Association
  belongs_to :forum
  #Auth Piggyback
  auth_belongs_to_parent :forum

====auth_has_many_parents

- association REQUIRED, What association to follow.
- :user_scope => A symbol representing a named_scope that takes in a user object to condition the association. It is recommended that you use this for performance reasons.

Example:

  #In Membership class
  named_scope :with_user, lambda { |user| {:conditions => {:user_id => user}}}
  #Association
  has_many :memberships
  #Auth Piggyback
  auth_has_many_parents :memberships, :user_scope => :with_user

===Instance Methods

Into every acts_as_authorizable model one instance method is injected called authorized?(user_instance,permission)

===Advanced

You can have circular authorization dependencies. They will not result in infinite loops because the plugin colors the authorization graph while it searches for new permissions. Performance of the plugin is highly dependent on how you use it. Putting the obvious belongs_to_user permissions lexically first will result in better performance. Minimizing the number of auth_parents is also a good way of ensuring higher performance. The queries that result from the authorization plugins work are based on the associations passed. Hence ActiveRecords caching will work just fine as well.



Copyright (c) 2008 <NAME>, released under the MIT license
{'fraction_non_alphanumeric': 0.047086473782316236, 'fraction_numerical': 0.0011346138260799091, 'mean_word_length': 4.269000853970965, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4644412', 'n_tokens_mistral': 3263, 'n_tokens_neox': 3138, 'n_words': 1543}