allowy 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/README.md +59 -18
  2. data/lib/allowy/version.rb +1 -1
  3. metadata +12 -12
data/README.md CHANGED
@@ -3,21 +3,23 @@
3
3
  Allowy is the authorization library that doesn't enforce tight DSL on you.
4
4
  It is very simple yet powerful.
5
5
 
6
- If you have any questions please contact me [@dnagir](http://www.ApproachE.com).
7
-
8
6
  ## Why another one?
9
7
 
10
8
  I've been using really great [cancan](https://github.com/ryanb/cancan) gem by Ryan Bates for a long time.
11
9
  It does its job amazingly well.
12
10
 
11
+ Allowy is basically the result of refactoring the CanCan Ability class. I then extracted it into a gem.
12
+
13
13
  CanCan doesn't work very well for me when Ability definitions grow above 20 lines or so:
14
14
 
15
- - it becomes **really** hard to track down why something was (or not) allowed.
16
- - DSL enforces you to use ActiveRecord-like scopes or block to fall back. Those grow and it gets hard to maintain.
17
- - The Ability class contains all the definitions for everything. Hard to test, hard to maintain.
15
+ - it becomes **really hard to track down** why something was (or not) allowed.
16
+ - **DSL enforces** you to use ActiveRecord-like scopes or blocks. It gets harder to maintain.
17
+ - The Ability class contains **all the definitions for everything**. Hard to test, hard to maintain unless carefully refactor it.
18
18
  - Implicit permission - CanCan tries to be very smart (and is indeed) using aliases such as `:manage` but it makes even harder to maintain.
19
19
  - Implicit permission - you can use any symbol to check permissions. `:love_people` will do, even if you never defined it.
20
- - A little bit tight to ORM. When using with database such as neo4j, some smalish things don't work. So I prefer to be explicit.
20
+ - A little bit **tight to ORM**. When using with database such as neo4j, some smalish things don't work. So I prefer to be explicit.
21
+ - **Testing** an ability for a single class often depends on too many others.
22
+ - **Refacoring** of the abilities feels like rolling your own authorization library.
21
23
 
22
24
  So I decided to put up allowy to solve those issue for me.
23
25
 
@@ -65,8 +67,8 @@ end
65
67
  # Then, in rails, you would use it:
66
68
  can? :view, page
67
69
  cannot? :edit, page
68
- authorize! :view, page # raises Allowy::AccessDenied if can?(:view, page) return false
69
- can? :love_people, page # Will fail because `love_people` is not defined on the Access Control class
70
+ authorize! :view, page # raises Allowy::AccessDenied if can?(:view, page) returns false
71
+ can? :love_people, page # Will raise error because `love_people` is not defined on the Access Control class
70
72
  ```
71
73
 
72
74
  ## Context
@@ -80,19 +82,19 @@ class PageAccess
80
82
  include Allowy::AccessControl
81
83
 
82
84
  def view?(page)
85
+ return true if context.params[:hiddedn_hack_for_admin]
83
86
  context.user_signed_in? and page.published?
84
87
  end
85
88
  end
86
89
  ```
87
90
 
88
- If you want to change the context in Rails then just override it on a single controller or globally on the `ApplicationController`:
91
+ If you want to change the context in Rails then just override it in the controller or globally in the `ApplicationController`:
89
92
 
90
93
  ```ruby
91
- class DefaultAccess
92
- include Allowy::AccessControl
93
- # This will give you methods without the need to go to context object
94
- delegate :current_user, :to => :context
95
- delegate :current_company, :to => :context
94
+ class PagesController < ApplicationController
95
+ def allowy_context
96
+ {realy: 'anything', can_be: 'here', event: params}
97
+ end
96
98
  end
97
99
  ```
98
100
 
@@ -104,16 +106,22 @@ I recommend creating your own base class to provide common context and maybe som
104
106
  ```ruby
105
107
  class DefaultAccess
106
108
  include Allowy::AccessControl
109
+ delegate :current_user, :to => :context
110
+ delegate :current_company, :to => :context
111
+
112
+ def domain_name
113
+ context.request.host
114
+ end
107
115
  end
108
116
  ```
109
117
 
110
- Then you can create multiple access control classes much easier:
118
+ Then you can create multiple access control classes:
111
119
 
112
120
  ```ruby
113
121
  class PageAccess < DefaultAccess
114
122
  # can? :view, page
115
123
  def view?(page)
116
- page and page.published?
124
+ page and page.published? and domain_name =~ /^www\./i
117
125
  end
118
126
 
119
127
  # can? :edit, page
@@ -124,6 +132,7 @@ class PageAccess < DefaultAccess
124
132
  # can? :create, WikiPage
125
133
  def create?(page_class)
126
134
  # We can do something with WikiPage here if we need to
135
+ return false if page_class.count >= 2 # only 2 wiki pages allowed
127
136
  # but can just ignore it and authorize based on current context only
128
137
  current_user and current_user.admin?
129
138
  end
@@ -136,13 +145,40 @@ class PageAccess < DefaultAccess
136
145
  end
137
146
  ```
138
147
 
148
+ In your controller:
149
+
150
+ ```ruby
151
+ class PagesController < ApplicationController
152
+ def show
153
+ @page = Page.find(params[:id])
154
+ authorize! :view, @page # It will raise if declined
155
+ # can?, cannot? can be used too
156
+ end
157
+
158
+ # Add this to the ApplicationController to handle it globally
159
+ rescue_from Allowy::AccessDenied do |exception|
160
+ logger.debug "Access denied on #{exception.action} #{exception.subject.inspect}"
161
+ redirect_to new_user_session_url, :alert => exception.message
162
+ end
163
+ end
164
+ ```
165
+
166
+ In your views:
167
+
168
+ ```haml
169
+ # app/views/pages/show.html.haml
170
+
171
+ %h1= @page.name
172
+ = link_to "Edit", edit_page_path if can? :edit, @page
173
+ ```
174
+
139
175
 
140
176
  # Testing with RSpec
141
177
 
142
178
  To test the access control classes you can just instantiate those passing context as a parameter.
143
- Most of the times you will stub out the context, so more isolated is a piece of cake.
179
+ Most of the time you will stub out the context, so the test isolation is a piece of cake.
144
180
 
145
- You need to `require 'allowy/rspec'` to enable the RSpec matchers and Rails controller extensions.
181
+ You need to `require 'allowy/rspec'`.
146
182
  It will give you RSpec matcher `be_able_to` and `ignore_authorization!` macro for controller specs.
147
183
 
148
184
 
@@ -156,6 +192,11 @@ describe PageAccess do
156
192
  describe "#view" do
157
193
  it { should_not be_able_to :view, page }
158
194
 
195
+ # Or without the matcher
196
+ it "should not allow" do
197
+ subject.view?(page).should be_false
198
+ end
199
+
159
200
  context "when published" do
160
201
  before { page.publish! }
161
202
  it { should be_able_to :view, page }
@@ -1,3 +1,3 @@
1
1
  module Allowy
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: allowy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-07 00:00:00.000000000 Z
12
+ date: 2012-01-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &70137337531820 !ruby/object:Gem::Requirement
16
+ requirement: &70173734581140 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70137337531820
24
+ version_requirements: *70173734581140
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &70137337531300 !ruby/object:Gem::Requirement
27
+ requirement: &70173734580640 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70137337531300
35
+ version_requirements: *70173734580640
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: pry
38
- requirement: &70137337530860 !ruby/object:Gem::Requirement
38
+ requirement: &70173734579780 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70137337530860
46
+ version_requirements: *70173734579780
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: guard
49
- requirement: &70137337530240 !ruby/object:Gem::Requirement
49
+ requirement: &70173734578960 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70137337530240
57
+ version_requirements: *70173734578960
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: guard-rspec
60
- requirement: &70137337529580 !ruby/object:Gem::Requirement
60
+ requirement: &70173734578340 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70137337529580
68
+ version_requirements: *70173734578340
69
69
  description: Allowy provides CanCan-like way of checking permission but doesn't enforce
70
70
  a tight DSL giving you more control
71
71
  email: