Skip to content

yatish27/granity

Repository files navigation

Granity

Granity is a fine-grained authorization engine for Ruby on Rails applications. It provides a flexible DSL for defining authorization rules and efficient permission checking.

Installation

Add this gem to your application's Gemfile:

gem 'granity'

Then execute:

$ bundle install

Run the migrations:

rails granity:install:migrations
rails db:migrate

Configuration

Create an initializer for Granity:

# config/initializers/granity.rb
Granity.configure do |config|
  config.cache_provider = Rails.cache # Optional: Uses Rails.cache if provided
  config.cache_ttl = 10.minutes
  config.max_cache_size = 10_000
  config.enable_tracing = !Rails.env.production?
  config.max_traversal_depth = 10
end

Defining Authorization Schema

Use the Granity DSL to define your authorization schema:

# config/initializers/granity.rb
Granity.define do
  resource_type :user do
    # User schema
  end

  resource_type :document do
    relation :owner, type: :user
    relation :viewer, type: :user
    relation :team, type: :team

    permission :view do
      include_any do
        include_relation :owner
        include_relation :viewer
        include_relation :admin from :team
      end
    end

    permission :edit do
      include_relation :owner
    end
  end

  resource_type :team do
    relation :member, type: :user
    relation :admin, type: :user
  end
end

Usage

Checking Permissions

# Check if a user has permission on a resource
if Granity.check_permission(
  subject_type: 'user',
  subject_id: current_user.id,
  permission: 'view',
  resource_type: 'document',
  resource_id: document.id
)
  # User can view the document
end

Creating Relations

# Grant a user owner access to a document
Granity.create_relation(
  object_type: 'document',
  object_id: document.id,
  relation: 'owner',
  subject_type: 'user',
  subject_id: user.id
)

Finding Subjects

# Find all users who can view a document
viewers = Granity.find_subjects(
  resource_type: 'document',
  resource_id: document.id,
  permission: 'view'
)

Integration with Rails Controllers

class ApplicationController < ActionController::Base
  def authorize!(resource, permission)
    unless Granity.check_permission(
      subject_type: 'user',
      subject_id: current_user.id,
      permission: permission,
      resource_type: resource.model_name.singular,
      resource_id: resource.id
    )
      raise Unauthorized, "Not authorized to #{permission} this #{resource.model_name.human}"
    end
  end
end

class DocumentsController < ApplicationController
  def show
    @document = Document.find(params[:id])
    authorize!(@document, :view)
    # ...
  end

  def update
    @document = Document.find(params[:id])
    authorize!(@document, :edit)
    # ...
  end
end

DSL Reference

Resource Types

Define the entities in your authorization model:

resource_type :document do
  # Resource definition
end

Relations

Define relationships between resources:

relation :owner, type: :user
relation :parent_folder, type: :folder

Permissions

Define access rules with Boolean logic:

permission :view do
  include_any do
    include_relation :owner
    include_relation :viewer
    include_relation :editor
  end
end

Boolean Logic

Combine relations with include_any (OR) and include_all (AND):

permission :publish do
  include_all do
    include_relation :editor

    include_any do
      include_relation :approved
      include_relation :admin from :team
    end
  end
end

Permission Composition

Reuse and compose permissions:

permission :manage do
  include_permission :view
  include_permission :edit
  include_relation :owner
end

Relation Traversal

Follow paths through related resources:

include_relation :member from :team

License

The gem is available as open source under the terms of the MIT License.