Skip to content
This repository
Browse code

First pass at docs

  • Loading branch information...
commit 1b4be57f65b30d927440dfa88ba8cab644606c89 1 parent 319b520
Nathan Long authored March 09, 2012
102  README.md
Source Rendered
... ...
@@ -1,6 +1,29 @@
1 1
 # ModelCitizen
2 2
 
3  
-TODO: Write a gem description
  3
+## SUPER ALPHA VERSION
  4
+
  5
+## Overview
  6
+
  7
+ModelCitizen gives you a clean and easy way to say, in your Rails app, **who** is allowed to do **what** with your models.
  8
+
  9
+It assumes that you already have some kind of user object in your application.
  10
+
  11
+The goals of ModelCitizen are:
  12
+
  13
+- To allow broad, class-level rules. Examples: 
  14
+  - "Basic users cannot delete **any** Widget."
  15
+  - "Only admin users can create Offices."
  16
+
  17
+- To allow fine-grained, instance-level rules. Examples: 
  18
+  - "Management users can only edit schedules in their jurisdiction."
  19
+  - "Users can't create playlists more than 20 songs long unless they've paid."
  20
+
  21
+- To provide a clear syntax for permissions-based views. Example:
  22
+  - `link_to 'Edit Widget', edit_widget_path(@widget) if current_user.can_edit?(@widget)`
  23
+
  24
+- To gracefully handle any access violations: display a "you can't do that" screen and log the violation.
  25
+
  26
+- To do all of this **without cluttering** either your controllers or your models. This is done by letting Authorizer classes do most of the work. More on that below.
4 27
 
5 28
 ## Installation
6 29
 
@@ -16,16 +39,91 @@ Or install it yourself as:
16 39
 
17 40
     $ gem install model_citizen
18 41
 
  42
+## How it works
  43
+
  44
+In broad terms, the authorization process flows like this:
  45
+
  46
+- A request comes to a model, either the class or an instance, saying "can this user do this action to you?"
  47
+- The model passes that question to its Authorizer
  48
+- The Authorizer checks whatever user properties and business rules are relevant to answer that question.
  49
+- The answer is passed back up to the model, then back to the original caller
  50
+
19 51
 ## Usage
20 52
 
  53
+### Users
  54
+
  55
+Your user model (whatever you call it) should `include ModelCitizen::UserAbilities`. This defines methods like `can_edit?(resource)`, which are just nice shortcuts for `resource.editable_by?(user)`. (TODO: Add this module).
  56
+
21 57
 ### Models
22 58
 
23  
-`include ModelCitizen::Abilities`
  59
+In your models, simply `include ModelCitizen::Abilities`. This sets up both class-level and instance-level methods like `creatable_by?(user)`, etc, all of which delegate to the model's corresponding authorizer. For example, the `Rabbit` model would delegate to `RabbitAuthorizer`.
24 60
 
25 61
 ### Controllers
26 62
 
  63
+#### Basic Usage
  64
+
  65
+In your controllers, add this method call:
  66
+
27 67
 `check_authorization_on ModelName`
28 68
 
  69
+That sets up a `:before_filter` that calls your class-level methods before each action. For instance, before running the `update` action, it will check whether `ModelName` is `updatable_by?` the current user at a class level. A return value of false means "this user can never update models of this class."
  70
+
  71
+If that's all you need, one line does it.
  72
+
  73
+#### In-action usage
  74
+
  75
+If you need to check some attributes of a model instance to decide if an action is permissible, you can use `check_authorization_for(:action, @model_instance, @user)` (TODO: determine this)
  76
+
  77
+### Authorizers
  78
+
  79
+Authorizers should be added under `app/authorizers`, one for each of your models. Each authorizer should correspond to a single model. So if you have `app/models/laser_cannon.rb`, you should have, at minimum:
  80
+
  81
+    # app/authorizers/laser_cannon_authorizer.rb
  82
+    class LaserCannonAuthorizer < ModelCitizen::Authorizer
  83
+    end
  84
+
  85
+These are where your actual authorization logic goes. You do have to specify your own business rules, but ModelCitizen comes with the following baked in:
  86
+
  87
+- All class-level methods defined on `ModelCitizen::Authorizer` return false by default; you must override them in your Authorizers to grant permissions. This whitelisting approach will keep you from accidentally allowing things you didn't intend.
  88
+- All instance-level methods defined on `ModelCitizen::Authorizer` call their corresponding class-level method by default.
  89
+
  90
+This combination means that, with this code:
  91
+
  92
+    # app/authorizers/laser_cannon_authorizer.rb
  93
+    class LaserCannonAuthorizer < ModelCitizen::Authorizer
  94
+    end
  95
+
  96
+... you can already do the following:
  97
+
  98
+    current_user.can_create?(LaserCannon)    # false; all inherited class-level permissions are false
  99
+    current_user.can_create?(@laser_cannon)  # false; instance-level permissions check class-level ones by default
  100
+
  101
+If you update your authorizer as follows:
  102
+
  103
+    # app/authorizers/laser_cannon_authorizer.rb
  104
+    class LaserCannonAuthorizer < ModelCitizen::Authorizer
  105
+
  106
+      def self.creatable_by?(user) # class-level permission
  107
+        true
  108
+      end
  109
+
  110
+      def deletable_by?(user)      # instance_level permission
  111
+        user.first_name == 'Larry' && Date.today.friday?
  112
+      end
  113
+
  114
+    end
  115
+
  116
+... you can now do this following:
  117
+
  118
+    current_user.can_create?(LaserCannon)    # true, per class method above
  119
+    current_user.can_create?(@laser_cannon)  # true; inherited instance method calls class method
  120
+    current_user.can_delete?(@laser_cannon)  # Only Larry, and only on Fridays
  121
+
  122
+## TODO
  123
+
  124
+- Add a module, to be included in whatever user class an app has, which defines all the `can_(verb)` methods.
  125
+- Determine exact syntax for checking rules during a controller action.
  126
+
29 127
 ## Contributing
30 128
 
31 129
 1. Fork it
2  lib/model_citizen/version.rb
... ...
@@ -1,3 +1,3 @@
1 1
 module ModelCitizen
2  
-  VERSION = "1.0.0"
  2
+  VERSION = "0.0.1"
3 3
 end

0 notes on commit 1b4be57

Please sign in to comment.
Something went wrong with that request. Please try again.