Thursday, April 1, 2010

Building your own permission system in ruby on rails.

If you're like me and have a application that's growing into a fairly complex application and certain pages are only accessible to certain users/groups then the best way to keep track of your permissions is to generate a permissions model to store the permissions data. This article is a step by step guide to creating a fully functioning permissions that should suit your applications needs.

Step 1, Create the UserPermission model.

script/generate model UserPermission controller:string action:string id_of_object:integer t.integer person_id:integer

You may or may not want to delete the t.timestamps out of the migration that was created for you in db/migrate (should be your newest migration, eg. 20100401043834_create_user_permissions.rb) as I don't feel timestamps are necessary for this type of data.

In your User model add:

has_many :user_permission

In your UserPermission model add:

belongs_to :person
validates_presence_of :controller
validates_presence_of :action
validates_presence_of :id_of_object
validates_presence_of :person_id


Step 2, Implement your before_filter method
Note you must already have your own method to access the current user to complete this step.
In this code example we access our current user with the @user variable (which in my code this is defined in a before_filter that executes on every page)

In app/controllers/application_controller.rb, write the following. I wrote mine under private.
def require_permission
   p =  = @user.user_permission.first(:conditions => "controller = '%s' and (action = '%s' OR action = '*')" % [params[:controller], params[:action]])
    if params[:id] and p
      unless p.id_of_object == params[:id].to_i or p.id_of_object == 0
        p = false
      end
    end
    unless p
      flash[:notice] = "Permission Denied"
      redirect_to :controller => 'people'
    end
end

Step 3, Implement
Add a before_filter :require_permission anywhere where you want this to execute.

Now lets create some permissions, I do this in my app console with the following code but you may create your own view from here to do this.

script/console production in your app directory to access console for your production environment (remove production for development environment)

Then type this:
p = @user.user_permission.new(:controller => 'posts', :action => '*', :id_of_object => 0); p.save

This will give you access to all objects and all actions for posts. * is a wildcard for :action and 0 is a wildcard for :id_of_objects, you can set this to something specific like :action => 'new' or set the :id_of_object to a specific number.

Anyways hope this helps, if any questions feel free to ask!

No comments: