Skip to content
Ultra lite authorization library
Branch: master
Clone or download
dzaporozhets Bump ruby image in CI
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Latest commit 81c77cf Mar 18, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib don't cover up actual errors Aug 3, 2016
spec Add vendor dir to simplecov filter Jan 10, 2018
.gitignore Update dependencies Jan 10, 2018
.gitlab-ci.yml Bump ruby image in CI Mar 18, 2019
.rspec init commit Aug 12, 2011
.travis.yml Remove jruby from travis tests May 10, 2017
CHANGELOG
Gemfile Update rspec Jan 10, 2018
Gemfile.lock Update rspec Jan 10, 2018
Guardfile Updated gems. Added Guard Sep 13, 2012
LICENSE license added Aug 18, 2011
README.md Fix typo on readme comment Mar 11, 2019
VERSION Bump version to 0.2.1 Jan 10, 2018
six-0.2.0.gem Update gemspec file Jan 10, 2018
six.gemspec

README.md

Six - is a ultra simple authorization gem for ruby!

pipeline status coverage report Code Climate

based on clear ruby it can be used for Rails applications or any other framework

Installation

  gem install six

QuickStart

4 steps:

  1. create abilities object

      abilities = Six.new
  2. create object/class with allowed method - here you'll put conditions to define abilities

    class BookRules
      def self.allowed(author, book)
        [:read_book, :edit_book]
      end
    end
  3. Add object with your rules to abilities

    abilities << BookRules # true
  4. Thats all. Now you can check abilities. In difference to CanCan it doesnt use current_user method. you manually pass object & subject.

    abilities.allowed?(@user, :read_book, @book) # true

Usage with Rails

# Controller

# application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery

  helper_method :abilities, :can?

  protected 

  def abilities
    @abilities ||= Six.new
  end

  # simple delegate method for controller & view
  def can?(object, action, subject)
    abilities.allowed?(object, action, subject)
  end
end

# books_controller.rb
class BooksController < ApplicationController
  before_action :add_abilities
  before_action :load_author

  def show
    @book = Book.find(params[:id])
    head(404) and return unless can?(:guest, :read_book, @book)
  end

  def edit
    @book = Book.find(params[:id])
    head(404) and return unless can?(@author, :edit_book, @book)
  end

  protected

  def add_abilities
    abilities << Book
  end

  def load_author
    @author = Author.find_by_id(params[:author_id])
  end
end


# Model
class Book < ActiveRecord::Base
  belongs_to :author

  def self.allowed(object, subject)
    rules = []
    return rules unless subject.instance_of?(Book)
    rules << :read_book if subject.public?
    rules << :edit_book if object && object.id == subject.author_id
    rules
  end
end

# View
link_to 'Edit', edit_book_path(book) if can?(@author, :edit_book, @book)

Ruby Usage

class BookRules
  # All authorization works on objects with method 'allowed'
  # No magic behind the scene
  # You can put this method to any class or object you want
  # It should always return array
  # And be ready to get nil in args
  def self.allowed(author, book)
    rules = []

    # good practice is to check for object type
    return rules unless book.instance_of?(Book)

    rules << :read_book if book.published? 
    rules << :edit_book if book.author?(author)

    # you are free to write any conditions you need
    if book.author?(author) && book.is_approved? # ....etc...
      rules << :publish_book 
    end

    rules # return array of abilities
  end
end

# create abilities object
abilities = Six.new

# add rules
abilities << BookRules # true

# thats all - now we can use it!

abilities.allowed? guest, :read_book, unpublished_book # false
abilities.allowed? guest, :read_book, published_book # true
abilities.allowed? guest, :edit_book, book # false
abilities.allowed? author, :edit_book, book # true
abilities.allowed? guest, :remove_book, book # false

:initialization

# simple
abilities = Six.new

# with rules
abilities = Six.new(:book_rules => BookRules) # same as Six.new & add(:book_rules, BookRules)

# with more
abilities = Six.new(:book => BookRules,
                    :auth => AuthRules,
                    :managment => ManagerRules)

Adding rules

abilities = Six.new

# 1. simple (recommended)
# but you cant use  abilities.use(:book_rules) to 
# search over book namespace only
abilities << BookRules

# 2. advanced
# now you can use  abilities.use(:book_rules) to 
# search over book namespace only
abilities.add(:book_rules, BookRules)

:allowed?

abilities = Six.new

abilities << BookRules

abilities.allowed? @guest, :read_book, @book # true
abilities.allowed? @guest, :edit_book, @book # false
abilities.allowed? @guest, :rate_book, @book # true

abilities.allowed? @guest, [:read_book, :edit_book], @book # false
abilities.allowed? @guest, [:read_book, :rate_book], @book # true

:use

abilities.add(:book_rules, BookRules)
abilities.add(:car_rules, CarRules)

abilities.allowed? ... # scan for both BookRules & CarRules & require kind_of check

abilities.use(:book_rules)
abilities.allowed? ... # use rules from BookRules only -> more perfomance

Namespaces

class BookRules
  def self.allowed(author, book)
    [:read_book, :edit_book, :publish_book] 
  end
end

class CarRules
  def self.allowed(driver, car)
    [:drive, :sell] 
  end
end

# init object
abilities = Six.new

# add packs with namespace support
abilities.add(:book, BookRules) # true
abilities.add(:car, CarRules)   # true
abilities.add(:ufo, nil)        # false
abilities.add!(:ufo, nil)       # raise Six::InvalidPackPassed


# use specific pack for rules (namespace)
abilities.use(:book) # true
abilities.allowed? :anyone, :read_book, book # true
abilities.allowed? :anyone, :drive, car # false

abilities.use(:car)
abilities.allowed? :anyone, :drive, :any      # true
abilities.allowed? :anyone, :read_book, :any  # false

# use reset to return to global usage
abilities.reset_use
abilities.allowed? :anyone, :drive, :any     # true
abilities.allowed? :anyone, :read_book, :any # true

# different use methods
abilities.use(:ufo)  # false
abilities.use!(:ufo) # raise Six::NoPackError


# remove pack
abilities.remove(:book)  # true
abilities.remove(:ufo)   # false
abilities.remove!(:ufo)  # raise Six::NoPackError

abilities.use(:car)  # true
abilities.current_rule_pack # :car
You can’t perform that action at this time.