Git Product home page Git Product logo

cannabis's Introduction

Cannabis

Very simple permissions that I have used on my last several projects so I figured it was time to abstract and wrap up into something more easily reusable.

Cans

Whatever class you want all permissions to run through should include Cannabis::Cans.

class User
  include MongoMapper::Document
  include Cannabis::Cans
end

This means that an instance of a user automatically gets can method for the default REST actions: can?(:view, resource), can?(:create, resource), can?(:update, resource), can?(:destroy, resource).

Ables

Each of the can methods simply calls the related “able” method (viewable, creatable, updatable, destroyable) for the action (view, create, update, delete). Cannabis comes with defaults for this methods that you can then override as makes sense for your permissions.

class Article
  include MongoMapper::Document
  include Cannabis::Ables
end

Including Cannabis::Ables adds the able methods to the class including it. In this instance, article now has viewable_by?(user), creatable_by?(user), updatable_by?(user) and destroyable_by?(user).

Lets say an article can be viewed and created by anyone, but only updated or destroyed by the user that created the article. To do that, you could leave viewable_by? and creatable_by? alone as they default to true and just override the other methods.

class Article
  include MongoMapper::Document
  include Cannabis::Ables
  userstamps! # adds creator and updater

  def updatable_by?(user)
    creator == user
  end

  def destroyable_by?(user)
    updatable_by?(user)
  end
end

Lets look at some sample code now:

john = User.create(:name => 'John')
steve = User.create(:name =. 'Steve')

ruby = Article.new(:title => 'Ruby')
john.can?(:create, ruby) # true
steve.can?(:create, ruby) # true

ruby.creator = john
ruby.save

john.can?(:view, ruby) # true
steve.can?(:view, ruby) # true

john.can?(:update, ruby) # true
steve.can?(:update, ruby) # false

john.can?(:destroy, ruby) # true
steve.can?(:destroy, ruby) # false

Now we can implement our permissions for each resource and then always check whether a user can or cannot do something. This makes it all really easy to test. Next, how would you use this in the controller.

Enforcers

class ApplicationController
  include Cannabis::Enforcers
end

Including Cannabis::Enforcers adds an enforce permission method for each of the actions defined (by default view/create/update/destroy). It is the same thing as doing this for each Cannabis action:

class ApplicationController
  include Cannabis::Enforcers

  delegate :can?, :to => :current_user
  helper_method :can? # so you can use it in your views
  hide_action :can?

  private

  def authorize!(action, resource)
    raise Cannabis::Exceptions::Transgression unless can?(action, resource)
  end
end

Which means you can use it like this:

class ArticlesController < ApplicationController
  def show
    @article = Article.find!(params[:id])
    authorize!(:view, @article)
  end
end

If the user can? :view the article, all is well. If not, a Cannabis::Exceptions::Transgression is raised which you can decide how to handle (show 404, slap them on the wrist, etc.).

Adding Your Own Actions

You can add your own actions like this:

Cannabis.add(:publish, :publishable)

The first parameter is the can method (ie: can? :publish) and the second is the able method (ie: publishable_by?).

Review

So, lets review: cans go on user model, ables go on everything, you override ables in each model where you want to enforce permissions, and enforcers go after each time you find or initialize an object in a controller. Bing, bang, boom.

Copyright © 2010 John Nunemaker. See LICENSE for details.

cannabis's People

Contributors

jnunemaker avatar

Stargazers

Rafał Trojanowski avatar Steve Hill avatar Tomasz Szymczyszyn avatar Piotr Sarnacki avatar

Watchers

Ewa Limanówka avatar Michał Krzyżanowski avatar James Cloos avatar Bury avatar Łukasz Strzebińczyk avatar Michał Dulat avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.