regulator 0.1.2 → 0.1.3

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.
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