<commit_before>h1. Guard the Rails Controller Actions

h2. installation for rails3

p. just add

bc.         gem 'ixtlan-guard'

p. into your _Gemfile_

h2. how it works

p. the main idea is like a posix authorization with a user belonging to one or more groups. each rails controller gets a *Guard* which maps each action of the controller to a set of allowed groups.

p. the default block which retrieves the logged in user from *current_user* method of the controller and collect the groups of this user. which makes it compatible with _restful_authentication_. in case there are no current_user the Guard will allow everything assuming there have no authentication and no authorization for this controller.

bc.        Proc.new do |controller|
          user = controller.send :current_user
          user.groups if user
        end

p. you can define a superuser group which default is *root* and that group is implicit added to all guards.

bc.         class UsersGuard
          def initialize(guard)
            guard.aliases = {:new=>:create, :edit=>:update}
            guard.actions= {
              :index => [:users],
              :show => [:users],
              :create => [:users],
              :update => [:users],
              :destroy => [:users]
            }
          end
        end


h2. restrict the access even further

p. assume you can translate your web application and have a translator group but you want to restrict each translator to its language. then you can use the guard to enforce this restriction.

p. let's add the following to your TranslationsController

bc. before-filter :locale_authorization
    skip-before-filter :authorization
    def locale_authorization
      @locale = Locale.find_by_code(params[:locale])
      authorization do |group| 
        if controller.respond_to? :current_user
          user = self.send :current_user
	  !GroupsLocalesUsers.first(:conditions => ["user_id = ? AND group_name = ? AND locale_name = ?", user.id, group.to_s, @locale).nil?
      	end
      end
    end

p. this you can easily use for other use cases like having different domains. each domain has its own set of users. even allowing users to be associated with more then one domain.

h2. allowed? method in controller/view

p. both the rails controller as well the view have a methods *allowed?* to ask the guard if a particular action is allowed by the *current_user*.

p. the controller *allowed?* just needs the action as argument.

p. the view *allowed?* needs the resource name and the action to answer the quest.

h2. rails3 generators

p. per default the *scaffold*, *resource* and *controller* will add a guard for the actions of the generated controller. the views of the scaffold will use *allowed?* to determine if a link or button leads to an action which is allowed for the *current_user*

h2. maintanance mode

p. since the guard is the ideal place to temporary disallow or block some groups, the guard offers some helper methods for this:
* block_groups(array_of_groups)
* blocked_groups
* current_user_restricted?(controller)
with this you can easily block all groups but the *root* which remains as it is.<commit_msg>added a few lines of docu<commit_after>h1. Guard the Rails Controller Actions

h2. installation for rails3

p. just add

bc.         gem 'ixtlan-guard'

p. into your _Gemfile_

h2. how it works

p. the main idea is like a posix authorization with a user belonging to one or more groups. each rails controller gets a *Guard* which maps each action of the controller to a set of allowed groups.

p. the default block which retrieves the logged in user from *current_user* method of the controller and collect the groups of this user. which makes it compatible with _restful_authentication_. in case there are no current_user the Guard will allow everything assuming there have no authentication and no authorization for this controller.

bc.        Proc.new do |controller|
          user = controller.send :current_user
          user.groups if user
        end

p. you can define a superuser group which default is *root* and that group is implicit added to all guards.

bc.         class UsersGuard
          def initialize(guard)
            guard.aliases = {:new=>:create, :edit=>:update}
            guard.actions= {
              :index => [:users],
              :show => [:users],
              :create => [:users],
              :update => [:users],
              :destroy => [:users]
            }
          end
        end


h2. restrict the access even further

p. assume you can translate your web application and have a translator group but you want to restrict each translator to its language. then you can use the guard to enforce this restriction.

p. let's add the following to your TranslationsController

bc. before-filter :locale_authorization
    skip-before-filter :authorization
    def locale_authorization
      @locale = Locale.find_by_code(params[:locale])
      authorization do |group| 
        if controller.respond_to? :current_user
          user = self.send :current_user
	  !GroupsLocalesUsers.first(:conditions => ["user_id = ? AND group_name = ? AND locale_name = ?", user.id, group.to_s, @locale).nil?
      	end
      end
    end

p. this you can easily use for other use cases like having different domains. each domain has its own set of users. even allowing users to be associated with more then one domain.

h2. allowed? method in controller/view

p. both the rails controller as well the view have a methods *allowed?* to ask the guard if a particular action is allowed by the *current_user*.

p. the controller *allowed?* just needs the action as argument.

p. the view *allowed?* needs the resource name and the action to answer the quest.

h2. rails3 generators

p. per default the *scaffold*, *resource* and *controller* will add a guard for the actions of the generated controller. the views of the scaffold will use *allowed?* to determine if a link or button leads to an action which is allowed for the *current_user*

h2. maintanance mode

p. since the guard is the ideal place to temporary disallow or block some groups, the guard offers some helper methods for this:
* block_groups(array_of_groups)
* blocked_groups
* current_user_restricted?(controller)
with this you can easily block all groups but the *root* which remains as it is.

h2. play together with authentication frameworks

p. the guard plays nicely together with authentication frameworks like *restful-authentication*, *devise* or any homegrown authentication which provides a *current_user* method for all controllers. see demo of that gem.

p. even if you can not provide *current_user* method you can use the guard with a custom block. pass in an block on initialization which returns the current user from somewhere. for example add something like this in an confug/initializer:

bc. Rails.configuration.guard.block = Proc.new { Session.user }

h2. other authorization libraries

p. *cancan* . . . 
{'fraction_non_alphanumeric': 0.06074899942824471, 'fraction_numerical': 0.002858776443682104, 'mean_word_length': 3.2201447527141136, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, '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': '948120', 'n_tokens_mistral': 1832, 'n_tokens_neox': 1782, 'n_words': 933}