allowy 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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: