regulator 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 911cd1700d6c57b00ca93599c53af6b38aeb5e29
4
- data.tar.gz: 483493a6ff6ddc269e374fedb22a3df20b917f6a
3
+ metadata.gz: 10e47763e8d217437980f1f09a6a7c4ab32ba1a2
4
+ data.tar.gz: f7326022562fbef9b9d0e386592fce817715316c
5
5
  SHA512:
6
- metadata.gz: 5b2d0979c34ac379599b231e43aa79954a247a5c4bcac14379cce38a264d462258f98ee9e474f7954a84c1ea2df92630efb9c8ac55e021f2f67fb5d423e20143
7
- data.tar.gz: 3ea1165fa80b0d4caf10a07f9496dd623fe31f81c9c1cd49f3108eb7e046cd1fbbe448e3a718d735505f2f0d3da1f21cd967c53342881aa53416d8650e44acff
6
+ metadata.gz: 62e40309efbf5f2a5f31abd664e1f7c05ace0cfbfb9ed690e9eb419538c8d3ab92095499654b5d09aa40adae82c8a2f500ed5ef565e6eb850a88c379a7fd5744
7
+ data.tar.gz: 9a0ee8202586ced8b054792cd66e11f94fa315dc981ef9708b833c94073d97ad3b00c97a2eec56819d60a3666cd10d5a66d043e4e488d54702cffaa5553f645c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Regulator
2
2
 
3
+ ## 0.1.3 (2015-07-29)
4
+ - made Regulator::PolicyFinder.new a bit more nimble
5
+ - included a simple activeadmin adapter that can be 'required' instead of generated
6
+
3
7
  ## 0.1.2 (2015-07-23)
4
8
  - Add generators for install, policy, and activeadmin adapter
5
9
 
data/README.md CHANGED
@@ -13,18 +13,6 @@ I built this because I believe authorization should be controller-based, not mod
13
13
 
14
14
  Why not contribute to pundit? [It's](https://github.com/elabs/pundit/issues/12) [been](https://github.com/elabs/pundit/issues/178) an [on going](https://github.com/elabs/pundit/search?q=namespace&type=Issues&utf8=%E2%9C%93) 'issue' in pundit and it doesn't look [like it'll be reality.](https://github.com/elabs/pundit/pull/190#issuecomment-53052356)
15
15
 
16
- ## TODOs
17
- * [ ] documentation
18
- * [ ] Usage section below, mock pundit's
19
- * [ ] yard doc
20
- * [ ] Lotus examples
21
- * [ ] Grape examples
22
- * [ ] ROM examples
23
- * [ ] Custom permissions examples
24
- * [ ] RoleModel gem examples
25
- * [ ] rolify gem examples
26
- * [ ] contributing wiki
27
-
28
16
  ## Installation
29
17
 
30
18
  Add this line to your application's Gemfile:
@@ -32,7 +20,6 @@ Add this line to your application's Gemfile:
32
20
  ```ruby
33
21
  gem 'regulator'
34
22
  ```
35
-
36
23
  And then execute:
37
24
 
38
25
  $ bundle
@@ -41,24 +28,29 @@ Or install it yourself as:
41
28
 
42
29
  $ gem install regulator
43
30
 
44
- ## Usage
31
+ Include Regulator in your application controller:
45
32
 
46
- No docs yet, check out the [specs](https://github.com/coryodaniel/regulator/blob/master/spec/regulator_spec.rb)
33
+ ``` ruby
34
+ class ApplicationController < ActionController::Base
35
+ include Regulator
36
+ protect_from_forgery
37
+ end
38
+ ```
47
39
 
48
- ### Generators
40
+ ## Generators
49
41
 
50
42
  Install regulator
51
- ```bash
43
+ ``` sh
52
44
  rails g regulator:install
53
45
  ```
54
46
 
55
47
  Create a new policy and policy test/spec
56
- ```bash
48
+ ``` sh
57
49
  rails g regulator:policy User
58
50
  ```
59
51
 
60
52
  Regulator comes with a generator for creating an ActiveAdmin adapter
61
- ```bash
53
+ ``` sh
62
54
  rails g regulator:activeadmin
63
55
  ```
64
56
 
@@ -84,6 +76,177 @@ config.regulator_policy_namespace = nil
84
76
  config.regulator_default_policy = nil
85
77
  ```
86
78
 
79
+ ## Policies
80
+
81
+ Regulator is focused around the notion of policy classes. We suggest that you put
82
+ these classes in `app/policies`. This is a simple example that allows updating
83
+ a post if the user is an admin, or if the post is unpublished:
84
+
85
+ ``` ruby
86
+ class PostPolicy
87
+ attr_reader :user, :post
88
+
89
+ def initialize(user, post)
90
+ @user = user
91
+ @post = post
92
+ end
93
+
94
+ def update?
95
+ user.admin? or not post.published?
96
+ end
97
+ end
98
+ ```
99
+
100
+ Regulator makes the following assumptions about this class:
101
+
102
+ - The class has the name `Scope` and is nested under the policy class.
103
+ - The first argument is a user. In your controller, Regulator will call the
104
+ `current_user` method to retrieve what to send into this argument.
105
+ - The second argument is a scope of some kind on which to perform some kind of
106
+ query. It will usually be an ActiveRecord class or a
107
+ `ActiveRecord::Relation`, but it could be something else entirely.
108
+ - Instances of this class respond to the method `resolve`, which should return
109
+ some kind of result which can be iterated over. For ActiveRecord classes,
110
+ this would usually be an `ActiveRecord::Relation`.
111
+
112
+ You'll probably want to inherit from the application policy scope generated by the
113
+ generator, or create your own base class to inherit from:
114
+
115
+ ``` ruby
116
+ class PostPolicy < ApplicationPolicy
117
+ class Scope < Scope
118
+ def resolve
119
+ if user.admin?
120
+ scope.all
121
+ else
122
+ scope.where(:published => true)
123
+ end
124
+ end
125
+ end
126
+
127
+ def update?
128
+ user.admin? or not post.published?
129
+ end
130
+ end
131
+ ```
132
+
133
+ You can now use this class from your controller via the `policy_scope` method:
134
+
135
+ ``` ruby
136
+ def index
137
+ @posts = policy_scope(Post)
138
+ end
139
+ ```
140
+
141
+ Just as with your policy, this will automatically infer that you want to use
142
+ the `PostPolicy::Scope` class, it will instantiate this class and call
143
+ `resolve` on the instance. In this case it is a shortcut for doing:
144
+
145
+ ``` ruby
146
+ def index
147
+ @posts = PostPolicy::Scope.new(current_user, Post).resolve
148
+ end
149
+ ```
150
+
151
+ You can, and are encouraged to, use this method in views:
152
+
153
+ ``` erb
154
+ <% policy_scope(@user.posts).each do |post| %>
155
+ <p><%= link_to post.title, post_path(post) %></p>
156
+ <% end %>
157
+ ```
158
+
159
+ ## Manually specifying policy classes
160
+
161
+ Sometimes you might want to explicitly declare which policy to use for a given
162
+ class, instead of letting Regulator infer it. This can be done like so:
163
+
164
+ Regulator supports the Pundit-style model "policy_class", but also implements it
165
+ at the controller level. You can also set a controller's policy_namespace if you want to use an alternate namespace to the one the controller is in.
166
+
167
+
168
+ ``` ruby
169
+ # Model level
170
+ class Post
171
+ def self.policy_class
172
+ PostablePolicy
173
+ end
174
+ end
175
+ ```
176
+
177
+ ``` ruby
178
+ # Controller level
179
+ class Api::Post
180
+ # By default, Regulator will look for Api::PostPolicy
181
+ def self.policy_class
182
+ PostPolicy
183
+ end
184
+ end
185
+ ```
186
+
187
+ ``` ruby
188
+ # Here the admin namespace could be told to use the same policy as the API namespace
189
+ class Admin::Post
190
+ # By default, Regulator will look for Admin::PostPolicy
191
+ def self.policy_class
192
+ PostPolicy
193
+ end
194
+
195
+ # You can also set it at the instance level
196
+ def policy_class
197
+ if current_user.is_a_high_paying_member?
198
+ HighClassPostPolicy
199
+ else
200
+ LowClassPostPolicy
201
+ end
202
+ end
203
+ end
204
+ ```
205
+
206
+ ``` ruby
207
+ class Admin::Comment
208
+ def self.policy_namespace
209
+ # Will make regulator look for ActiveAdmin::CommentPolicy instead of
210
+ # Admin::CommentPolicy
211
+ ActiveAdmin
212
+ end
213
+ end
214
+ ```
215
+
216
+ Of course ```policy_namespace``` and ```policy_class``` can be used together.
217
+
218
+ ## Policy Namespaces
219
+
220
+ This table explains what policies Regulator will look for in different scenarios:
221
+
222
+ | Controller Name | Model Name | Expected Policy |
223
+ | -------------------------------------------------------|------------------| -------------------------------|
224
+ | AlbumController | Album | AlbumPolicy |
225
+ | Api::AlbumController | Album | Api::AlbumPolicy |
226
+ | Admin::AlbumController | Album | Admin::AlbumPolicy |
227
+ | Admin::AlbumController.policy_namespace = 'SuperUser' | Album | SuperUser::AlbumPolicy |
228
+ | Admin::AlbumController.policy_namespace = nil | Album | AlbumPolicy |
229
+ | Admin::AlbumContoller | MySongGem::Album | Admin::MySongGem::AlbumPolicy |
230
+ | SongController#policy_class = TrackPolicy | Song | TrackPolicy |
231
+ | SongController.policy_class = Legacy::TrackPolicy | Song | Legacy::TrackPolicy |
232
+
233
+ ```policy_class``` at the controller-level is king. Setting it will override all logic for determining the policy to use.
234
+
235
+ ## ActiveAdmin Auth Adapter
236
+
237
+ There is a generator and an included adapter. Using the generator will place a more complex customizable adapter in your ```lib``` directory.
238
+
239
+ A simple adapter is also provided, to use add the following to your active_admin initializer:
240
+ ``` ruby
241
+ ActiveAdmin::Dependency.regulator!
242
+
243
+ require 'regulator'
244
+ require 'regulator/active_admin_adapter'
245
+ ActiveAdmin.setup do |config|
246
+ config.authorization_adapter = "Regulator::ActiveAdminAdapter"
247
+ ...
248
+ ```
249
+
87
250
  ## Development
88
251
 
89
252
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -96,7 +259,19 @@ The gem is available as open source under the terms of the [MIT License](http://
96
259
 
97
260
  ## Contributors
98
261
  * [Cory O'Daniel](http://linkedin.com/in/coryodaniel)
262
+ * All the hard work done on [Pundit](https://github.com/elabs/pundit)
99
263
 
100
264
  Thanks to Warren G for the inspiration, bro.
101
265
 
102
266
  ![Regulator](https://upload.wikimedia.org/wikipedia/commons/a/ac/Nat_Powers_%26_Warren_G.jpg)
267
+
268
+ ## TODOs
269
+ * [ ] documentation
270
+ * [ ] yard doc
271
+ * [ ] Lotus examples
272
+ * [ ] Grape examples
273
+ * [ ] ROM examples
274
+ * [ ] Custom permissions examples
275
+ * [ ] RoleModel gem examples
276
+ * [ ] rolify gem examples
277
+ * [ ] contributing wiki
@@ -0,0 +1,34 @@
1
+ module Regulator
2
+ class ActiveAdminAdapter < ActiveAdmin::AuthorizationAdapter
3
+ def authorized?(action, subject = nil)
4
+ policy = retrieve_policy(subject)
5
+ action = format_action(action, subject)
6
+ policy.respond_to?(action) && policy.public_send(action)
7
+ end
8
+
9
+ def scope_collection(collection, action = Auth::READ)
10
+ # scoping is appliable only to read/index action
11
+ # which means there is no way how to scope other actions
12
+ Regulator.policy_scope!(user, collection, self.resource.controller)
13
+ end
14
+
15
+ def retrieve_policy(subject)
16
+ case subject
17
+ when nil then Regulator.policy!(user, resource, self.resource.controller)
18
+ when Class then Regulator.policy!(user, subject.new, self.resource.controller)
19
+ else Regulator.policy!(user, subject, self.resource.controller)
20
+ end
21
+ end
22
+
23
+ def format_action(action, subject)
24
+ # https://github.com/elabs/regulator/blob/master/lib/generators/regulator/install/templates/application_policy.rb
25
+ case action
26
+ when ActiveAdmin::Auth::CREATE then :create?
27
+ when ActiveAdmin::Auth::UPDATE then :update?
28
+ when ActiveAdmin::Auth::READ then subject.is_a?(Class) ? :index? : :show?
29
+ when ActiveAdmin::Auth::DESTROY then subject.is_a?(Class) ? :destroy_all? : :destroy?
30
+ else "#{action}?"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -7,11 +7,31 @@ module Regulator
7
7
  def initialize(object, controller_or_namespace = nil)
8
8
  @object = object
9
9
 
10
- if controller_or_namespace.is_a?(Module)
10
+ if controller_or_namespace.instance_of? Module
11
+ # Its a Module
11
12
  @namespace = controller_or_namespace
13
+ elsif controller_or_namespace.instance_of? Class
14
+ # Controller Class
15
+ @controller = controller_or_namespace
16
+
17
+ # ActiveAdmin uses the Regulator API directly, it doesnt mix it into the controllers
18
+ @namespace = if @controller.respond_to?(:policy_namespace)
19
+ # if the controller explicitly sets the policy_namespace to we want to keep it nil
20
+ @controller.try(:policy_namespace)
21
+ else
22
+ @controller.parent
23
+ end
12
24
  elsif controller_or_namespace
25
+ # Controller Instance
13
26
  @controller = controller_or_namespace
14
- @namespace = @controller.policy_namespace
27
+
28
+ # ActiveAdmin uses the Regulator API directly, it doesnt mix it into the controllers
29
+ @namespace = if @controller.respond_to?(:policy_namespace)
30
+ # if the controller explicitly sets the policy_namespace to we want to keep it nil
31
+ @controller.try(:policy_namespace)
32
+ else
33
+ @controller.class.parent
34
+ end
15
35
  end
16
36
  end
17
37
 
@@ -1,3 +1,3 @@
1
1
  module Regulator
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: regulator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cory O'Daniel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-07-23 00:00:00.000000000 Z
11
+ date: 2015-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -159,6 +159,7 @@ files:
159
159
  - lib/generators/test_unit/policy_generator.rb
160
160
  - lib/generators/test_unit/templates/policy_test.rb
161
161
  - lib/regulator.rb
162
+ - lib/regulator/active_admin_adapter.rb
162
163
  - lib/regulator/policy_finder.rb
163
164
  - lib/regulator/rspec.rb
164
165
  - lib/regulator/version.rb