pundit 1.1.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,37 +1,38 @@
1
1
  # Pundit
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/elabs/pundit.svg?branch=master)](https://travis-ci.org/elabs/pundit)
4
- [![Code Climate](https://codeclimate.com/github/elabs/pundit.svg)](https://codeclimate.com/github/elabs/pundit)
5
- [![Inline docs](http://inch-ci.org/github/elabs/pundit.svg?branch=master)](http://inch-ci.org/github/elabs/pundit)
3
+ [![Build Status](https://secure.travis-ci.org/varvet/pundit.svg?branch=master)](https://travis-ci.org/varvet/pundit)
4
+ [![Code Climate](https://codeclimate.com/github/varvet/pundit.svg)](https://codeclimate.com/github/varvet/pundit)
5
+ [![Inline docs](http://inch-ci.org/github/varvet/pundit.svg?branch=master)](http://inch-ci.org/github/varvet/pundit)
6
6
  [![Gem Version](https://badge.fury.io/rb/pundit.svg)](http://badge.fury.io/rb/pundit)
7
7
 
8
8
  Pundit provides a set of helpers which guide you in leveraging regular Ruby
9
9
  classes and object oriented design patterns to build a simple, robust and
10
- scaleable authorization system.
10
+ scalable authorization system.
11
11
 
12
12
  Links:
13
13
 
14
- - [API documentation](http://www.rubydoc.info/gems/pundit)
15
- - [Source Code](https://github.com/elabs/pundit)
16
- - [Contributing](https://github.com/elabs/pundit/blob/master/CONTRIBUTING.md)
17
- - [Code of Conduct](https://github.com/elabs/pundit/blob/master/CODE_OF_CONDUCT.md)
14
+ - [API documentation for the most recent version](http://www.rubydoc.info/gems/pundit)
15
+ - [Source Code](https://github.com/varvet/pundit)
16
+ - [Contributing](https://github.com/varvet/pundit/blob/master/CONTRIBUTING.md)
17
+ - [Code of Conduct](https://github.com/varvet/pundit/blob/master/CODE_OF_CONDUCT.md)
18
18
 
19
19
  Sponsored by:
20
20
 
21
- [<img src="http://d3cv91luii1z1d.cloudfront.net/logo-gh.png" alt="Elabs" height="50px"/>](http://elabs.se)
21
+ [<img src="https://www.varvet.com/images/wordmark-red.svg" alt="Varvet" height="50px"/>](https://www.varvet.com)
22
22
 
23
23
  ## Installation
24
24
 
25
- ``` ruby
26
- gem "pundit"
25
+ > **Please note** that the README on GitHub is accurate with the _latest code on GitHub_. You are most likely using a released version of Pundit, so please refer to the [documentation for the latest released version of Pundit](https://www.rubydoc.info/gems/pundit).
26
+
27
+ ``` sh
28
+ bundle add pundit
27
29
  ```
28
30
 
29
- Include Pundit in your application controller:
31
+ Include `Pundit::Authorization` in your application controller:
30
32
 
31
33
  ``` ruby
32
34
  class ApplicationController < ActionController::Base
33
- include Pundit
34
- protect_from_forgery
35
+ include Pundit::Authorization
35
36
  end
36
37
  ```
37
38
 
@@ -61,7 +62,7 @@ class PostPolicy
61
62
  end
62
63
 
63
64
  def update?
64
- user.admin? or not post.published?
65
+ user.admin? || !post.published?
65
66
  end
66
67
  end
67
68
  ```
@@ -116,7 +117,9 @@ and the given record. It then infers from the action name, that it should call
116
117
  `authorize` would have done something like this:
117
118
 
118
119
  ``` ruby
119
- raise "not authorized" unless PostPolicy.new(current_user, @post).update?
120
+ unless PostPolicy.new(current_user, @post).update?
121
+ raise Pundit::NotAuthorizedError, "not allowed to update? this #{@post.inspect}"
122
+ end
120
123
  ```
121
124
 
122
125
  You can pass a second argument to `authorize` if the name of the permission you
@@ -131,6 +134,18 @@ def publish
131
134
  end
132
135
  ```
133
136
 
137
+ You can pass an argument to override the policy class if necessary. For example:
138
+
139
+ ```ruby
140
+ def create
141
+ @publication = find_publication # assume this method returns any model that behaves like a publication
142
+ # @publication.class => Post
143
+ authorize @publication, policy_class: PublicationPolicy
144
+ @publication.publish!
145
+ redirect_to @publication
146
+ end
147
+ ```
148
+
134
149
  If you don't have an instance for the first argument to `authorize`, then you can pass
135
150
  the class. For example:
136
151
 
@@ -151,6 +166,20 @@ def admin_list
151
166
  end
152
167
  ```
153
168
 
169
+ `authorize` returns the instance passed to it, so you can chain it like this:
170
+
171
+ Controller:
172
+ ```ruby
173
+ def show
174
+ @user = authorize User.find(params[:id])
175
+ end
176
+
177
+ # return the record even for namespaced policies
178
+ def show
179
+ @user = authorize [:admin, User.find(params[:id])]
180
+ end
181
+ ```
182
+
154
183
  You can easily get a hold of an instance of the policy through the `policy`
155
184
  method in both the view and controller. This is especially useful for
156
185
  conditionally showing links or buttons in the view:
@@ -167,14 +196,30 @@ you can retrieve it by passing a symbol.
167
196
 
168
197
  ```ruby
169
198
  # app/policies/dashboard_policy.rb
170
- class DashboardPolicy < Struct.new(:user, :dashboard)
171
- # ...
199
+ class DashboardPolicy
200
+ attr_reader :user
201
+
202
+ # _record in this example will just be :dashboard
203
+ def initialize(user, _record)
204
+ @user = user
205
+ end
206
+
207
+ def show?
208
+ user.admin?
209
+ end
172
210
  end
173
211
  ```
174
212
 
213
+ Note that the headless policy still needs to accept two arguments. The
214
+ second argument will just be the symbol `:dashboard` in this case which
215
+ is what is passed as the record to `authorize` below.
216
+
175
217
  ```ruby
176
218
  # In controllers
177
- authorize :dashboard, :show?
219
+ def show
220
+ authorize :dashboard, :show?
221
+ ...
222
+ end
178
223
  ```
179
224
 
180
225
  ```erb
@@ -184,54 +229,6 @@ authorize :dashboard, :show?
184
229
  <% end %>
185
230
  ```
186
231
 
187
- ## Ensuring policies are used
188
-
189
- Pundit adds a method called `verify_authorized` to your controllers. This
190
- method will raise an exception if `authorize` has not yet been called. You
191
- should run this method in an `after_action` to ensure that you haven't
192
- forgotten to authorize the action. For example:
193
-
194
- ``` ruby
195
- class ApplicationController < ActionController::Base
196
- after_action :verify_authorized
197
- end
198
- ```
199
-
200
- Likewise, Pundit also adds `verify_policy_scoped` to your controller. This
201
- will raise an exception in the vein of `verify_authorized`. However, it tracks
202
- if `policy_scope` is used instead of `authorize`. This is mostly useful for
203
- controller actions like `index` which find collections with a scope and don't
204
- authorize individual instances.
205
-
206
- ``` ruby
207
- class ApplicationController < ActionController::Base
208
- after_action :verify_authorized, except: :index
209
- after_action :verify_policy_scoped, only: :index
210
- end
211
- ```
212
-
213
- If you're using `verify_authorized` in your controllers but need to
214
- conditionally bypass verification, you can use `skip_authorization`. For
215
- bypassing `verify_policy_scoped`, use `skip_policy_scope`. These are useful
216
- in circumstances where you don't want to disable verification for the
217
- entire action, but have some cases where you intend to not authorize.
218
-
219
- ```ruby
220
- def show
221
- record = Record.find_by(attribute: "value")
222
- if record.present?
223
- authorize record
224
- else
225
- skip_authorization
226
- end
227
- end
228
- ```
229
-
230
- If you need to perform some more sophisticated logic or you want to raise a custom
231
- exception you can use the two lower level methods `pundit_policy_authorized?`
232
- and `pundit_policy_scoped?` which return `true` or `false` depending on whether
233
- `authorize` or `policy_scope` have been called, respectively.
234
-
235
232
  ## Scopes
236
233
 
237
234
  Often, you will want to have some kind of view listing records which a
@@ -241,8 +238,6 @@ define a class called a policy scope. It can look something like this:
241
238
  ``` ruby
242
239
  class PostPolicy < ApplicationPolicy
243
240
  class Scope
244
- attr_reader :user, :scope
245
-
246
241
  def initialize(user, scope)
247
242
  @user = user
248
243
  @scope = scope
@@ -255,10 +250,14 @@ class PostPolicy < ApplicationPolicy
255
250
  scope.where(published: true)
256
251
  end
257
252
  end
253
+
254
+ private
255
+
256
+ attr_reader :user, :scope
258
257
  end
259
258
 
260
259
  def update?
261
- user.admin? or not post.published?
260
+ user.admin? or not record.published?
262
261
  end
263
262
  end
264
263
  ```
@@ -291,7 +290,7 @@ class PostPolicy < ApplicationPolicy
291
290
  end
292
291
 
293
292
  def update?
294
- user.admin? or not post.published?
293
+ user.admin? or not record.published?
295
294
  end
296
295
  end
297
296
  ```
@@ -302,15 +301,26 @@ You can now use this class from your controller via the `policy_scope` method:
302
301
  def index
303
302
  @posts = policy_scope(Post)
304
303
  end
304
+
305
+ def show
306
+ @post = policy_scope(Post).find(params[:id])
307
+ end
308
+ ```
309
+
310
+ Like with the authorize method, you can also override the policy scope class:
311
+
312
+ ``` ruby
313
+ def index
314
+ # publication_class => Post
315
+ @publications = policy_scope(publication_class, policy_scope_class: PublicationPolicy::Scope)
316
+ end
305
317
  ```
306
318
 
307
- Just as with your policy, this will automatically infer that you want to use
308
- the `PostPolicy::Scope` class, it will instantiate this class and call
309
- `resolve` on the instance. In this case it is a shortcut for doing:
319
+ In this case it is a shortcut for doing:
310
320
 
311
321
  ``` ruby
312
322
  def index
313
- @posts = PostPolicy::Scope.new(current_user, Post).resolve
323
+ @publications = PublicationPolicy::Scope.new(current_user, Post).resolve
314
324
  end
315
325
  ```
316
326
 
@@ -322,6 +332,70 @@ You can, and are encouraged to, use this method in views:
322
332
  <% end %>
323
333
  ```
324
334
 
335
+ ## Ensuring policies and scopes are used
336
+
337
+ When you are developing an application with Pundit it can be easy to forget to
338
+ authorize some action. People are forgetful after all. Since Pundit encourages
339
+ you to add the `authorize` call manually to each controller action, it's really
340
+ easy to miss one.
341
+
342
+ Thankfully, Pundit has a handy feature which reminds you in case you forget.
343
+ Pundit tracks whether you have called `authorize` anywhere in your controller
344
+ action. Pundit also adds a method to your controllers called
345
+ `verify_authorized`. This method will raise an exception if `authorize` has not
346
+ yet been called. You should run this method in an `after_action` hook to ensure
347
+ that you haven't forgotten to authorize the action. For example:
348
+
349
+ ``` ruby
350
+ class ApplicationController < ActionController::Base
351
+ include Pundit::Authorization
352
+ after_action :verify_authorized
353
+ end
354
+ ```
355
+
356
+ Likewise, Pundit also adds `verify_policy_scoped` to your controller. This
357
+ will raise an exception similar to `verify_authorized`. However, it tracks
358
+ if `policy_scope` is used instead of `authorize`. This is mostly useful for
359
+ controller actions like `index` which find collections with a scope and don't
360
+ authorize individual instances.
361
+
362
+ ``` ruby
363
+ class ApplicationController < ActionController::Base
364
+ include Pundit::Authorization
365
+ after_action :verify_authorized, except: :index
366
+ after_action :verify_policy_scoped, only: :index
367
+ end
368
+ ```
369
+
370
+ **This verification mechanism only exists to aid you while developing your
371
+ application, so you don't forget to call `authorize`. It is not some kind of
372
+ failsafe mechanism or authorization mechanism. You should be able to remove
373
+ these filters without affecting how your app works in any way.**
374
+
375
+ Some people have found this feature confusing, while many others
376
+ find it extremely helpful. If you fall into the category of people who find it
377
+ confusing then you do not need to use it. Pundit will work just fine without
378
+ using `verify_authorized` and `verify_policy_scoped`.
379
+
380
+ ### Conditional verification
381
+
382
+ If you're using `verify_authorized` in your controllers but need to
383
+ conditionally bypass verification, you can use `skip_authorization`. For
384
+ bypassing `verify_policy_scoped`, use `skip_policy_scope`. These are useful
385
+ in circumstances where you don't want to disable verification for the
386
+ entire action, but have some cases where you intend to not authorize.
387
+
388
+ ```ruby
389
+ def show
390
+ record = Record.find_by(attribute: "value")
391
+ if record.present?
392
+ authorize record
393
+ else
394
+ skip_authorization
395
+ end
396
+ end
397
+ ```
398
+
325
399
  ## Manually specifying policy classes
326
400
 
327
401
  Sometimes you might want to explicitly declare which policy to use for a given
@@ -335,6 +409,16 @@ class Post
335
409
  end
336
410
  ```
337
411
 
412
+ Alternatively, you can declare an instance method:
413
+
414
+ ``` ruby
415
+ class Post
416
+ def policy_class
417
+ PostablePolicy
418
+ end
419
+ end
420
+ ```
421
+
338
422
  ## Just plain old Ruby
339
423
 
340
424
  As you can see, Pundit doesn't do anything you couldn't have easily done
@@ -362,7 +446,8 @@ rails g pundit:policy post
362
446
 
363
447
  In many applications, only logged in users are really able to do anything. If
364
448
  you're building such a system, it can be kind of cumbersome to check that the
365
- user in a policy isn't `nil` for every single permission.
449
+ user in a policy isn't `nil` for every single permission. Aside from policies,
450
+ you can add this check to the base class for scopes.
366
451
 
367
452
  We suggest that you define a filter that redirects unauthenticated users to the
368
453
  login page. As a secondary defence, if you've defined an ApplicationPolicy, it
@@ -376,6 +461,37 @@ class ApplicationPolicy
376
461
  @user = user
377
462
  @record = record
378
463
  end
464
+
465
+ class Scope
466
+ attr_reader :user, :scope
467
+
468
+ def initialize(user, scope)
469
+ raise Pundit::NotAuthorizedError, "must be logged in" unless user
470
+ @user = user
471
+ @scope = scope
472
+ end
473
+ end
474
+ end
475
+ ```
476
+
477
+ ## NilClassPolicy
478
+
479
+ To support a [null object pattern](https://en.wikipedia.org/wiki/Null_Object_pattern)
480
+ you may find that you want to implement a `NilClassPolicy`. This might be useful
481
+ where you want to extend your ApplicationPolicy to allow some tolerance of, for
482
+ example, associations which might be `nil`.
483
+
484
+ ```ruby
485
+ class NilClassPolicy < ApplicationPolicy
486
+ class Scope < Scope
487
+ def resolve
488
+ raise Pundit::NotDefinedError, "Cannot scope NilClass"
489
+ end
490
+ end
491
+
492
+ def show?
493
+ false # Nobody can see nothing
494
+ end
379
495
  end
380
496
  ```
381
497
 
@@ -388,8 +504,7 @@ method in every controller.
388
504
 
389
505
  ```ruby
390
506
  class ApplicationController < ActionController::Base
391
- protect_from_forgery
392
- include Pundit
507
+ include Pundit::Authorization
393
508
 
394
509
  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
395
510
 
@@ -397,11 +512,15 @@ class ApplicationController < ActionController::Base
397
512
 
398
513
  def user_not_authorized
399
514
  flash[:alert] = "You are not authorized to perform this action."
400
- redirect_to(request.referrer || root_path)
515
+ redirect_back(fallback_location: root_path)
401
516
  end
402
517
  end
403
518
  ```
404
519
 
520
+ Alternatively, you can globally handle Pundit::NotAuthorizedError's by having rails handle them as a 403 error and serving a 403 error page. Add the following to application.rb:
521
+
522
+ ```config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] = :forbidden```
523
+
405
524
  ## Creating custom error messages
406
525
 
407
526
  `NotAuthorizedError`s provide information on what query (e.g. `:create?`), what
@@ -422,7 +541,7 @@ class ApplicationController < ActionController::Base
422
541
  policy_name = exception.policy.class.to_s.underscore
423
542
 
424
543
  flash[:error] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default
425
- redirect_to(request.referrer || root_path)
544
+ redirect_back(fallback_url: root_path)
426
545
  end
427
546
  end
428
547
  ```
@@ -469,6 +588,47 @@ def pundit_user
469
588
  end
470
589
  ```
471
590
 
591
+ ## Policy Namespacing
592
+ In some cases it might be helpful to have multiple policies that serve different contexts for a
593
+ resource. A prime example of this is the case where User policies differ from Admin policies. To
594
+ authorize with a namespaced policy, pass the namespace into the `authorize` helper in an array:
595
+
596
+ ```ruby
597
+ authorize(post) # => will look for a PostPolicy
598
+ authorize([:admin, post]) # => will look for an Admin::PostPolicy
599
+ authorize([:foo, :bar, post]) # => will look for a Foo::Bar::PostPolicy
600
+
601
+ policy_scope(Post) # => will look for a PostPolicy::Scope
602
+ policy_scope([:admin, Post]) # => will look for an Admin::PostPolicy::Scope
603
+ policy_scope([:foo, :bar, Post]) # => will look for a Foo::Bar::PostPolicy::Scope
604
+ ```
605
+
606
+ If you are using namespaced policies for something like Admin views, it can be useful to
607
+ override the `policy_scope` and `authorize` helpers in your `AdminController` to automatically
608
+ apply the namespacing:
609
+
610
+ ```ruby
611
+ class AdminController < ApplicationController
612
+ def policy_scope(scope)
613
+ super([:admin, scope])
614
+ end
615
+
616
+ def authorize(record, query = nil)
617
+ super([:admin, record], query)
618
+ end
619
+ end
620
+
621
+ class Admin::PostController < AdminController
622
+ def index
623
+ policy_scope(Post)
624
+ end
625
+
626
+ def show
627
+ post = authorize Post.find(params[:id])
628
+ end
629
+ end
630
+ ```
631
+
472
632
  ## Additional context
473
633
 
474
634
  Pundit strongly encourages you to model your application in such a way that the
@@ -497,7 +657,7 @@ class UserContext
497
657
  end
498
658
 
499
659
  class ApplicationController
500
- include Pundit
660
+ include Pundit::Authorization
501
661
 
502
662
  def pundit_user
503
663
  UserContext.new(current_user, request.ip)
@@ -507,9 +667,8 @@ end
507
667
 
508
668
  ## Strong parameters
509
669
 
510
- In Rails 4 (or Rails 3.2 with the
511
- [strong_parameters](https://github.com/rails/strong_parameters) gem),
512
- mass-assignment protection is handled in the controller. With Pundit you can
670
+ In Rails,
671
+ mass-assignment protection is handled in the controller. With Pundit you can
513
672
  control which attributes a user has access to update via your policies. You can
514
673
  set up a `permitted_attributes` method in your policy like this:
515
674
 
@@ -533,7 +692,7 @@ You can now retrieve these attributes from the policy:
533
692
  class PostsController < ApplicationController
534
693
  def update
535
694
  @post = Post.find(params[:id])
536
- if @post.update_attributes(post_params)
695
+ if @post.update(post_params)
537
696
  redirect_to @post
538
697
  else
539
698
  render :edit
@@ -555,7 +714,7 @@ However, this is a bit cumbersome, so Pundit provides a convenient helper method
555
714
  class PostsController < ApplicationController
556
715
  def update
557
716
  @post = Post.find(params[:id])
558
- if @post.update_attributes(permitted_attributes(@post))
717
+ if @post.update(permitted_attributes(@post))
559
718
  redirect_to @post
560
719
  else
561
720
  render :edit
@@ -564,6 +723,45 @@ class PostsController < ApplicationController
564
723
  end
565
724
  ```
566
725
 
726
+ If you want to permit different attributes based on the current action, you can define a `permitted_attributes_for_#{action}` method on your policy:
727
+
728
+ ```ruby
729
+ # app/policies/post_policy.rb
730
+ class PostPolicy < ApplicationPolicy
731
+ def permitted_attributes_for_create
732
+ [:title, :body]
733
+ end
734
+
735
+ def permitted_attributes_for_edit
736
+ [:body]
737
+ end
738
+ end
739
+ ```
740
+
741
+ If you have defined an action-specific method on your policy for the current action, the `permitted_attributes` helper will call it instead of calling `permitted_attributes` on your controller.
742
+
743
+ If you need to fetch parameters based on namespaces different from the suggested one, override the below method, in your controller, and return an instance of `ActionController::Parameters`.
744
+
745
+ ```ruby
746
+ def pundit_params_for(record)
747
+ params.require(PolicyFinder.new(record).param_key)
748
+ end
749
+ ```
750
+
751
+ For example:
752
+
753
+ ```ruby
754
+ # If you don't want to use require
755
+ def pundit_params_for(record)
756
+ params.fetch(PolicyFinder.new(record).param_key, {})
757
+ end
758
+
759
+ # If you are using something like the JSON API spec
760
+ def pundit_params_for(_record)
761
+ params.fetch(:data, {}).fetch(:attributes, {})
762
+ end
763
+ ```
764
+
567
765
  ## RSpec
568
766
 
569
767
  ### Policy Specs
@@ -600,14 +798,33 @@ end
600
798
  An alternative approach to Pundit policy specs is scoping them to a user context as outlined in this
601
799
  [excellent post](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/) and implemented in the third party [pundit-matchers](https://github.com/chrisalley/pundit-matchers) gem.
602
800
 
801
+ ### Scope Specs
802
+
803
+ Pundit does not provide a DSL for testing scopes. Just test it like a regular Ruby class!
804
+
805
+ ### Linting with RuboCop RSpec
806
+
807
+ When you lint your RSpec spec files with `rubocop-rspec`, it will fail to properly detect RSpec constructs that Pundit defines, `permissions`.
808
+ Make sure to use `rubocop-rspec` 2.0 or newer and add the following to your `.rubocop.yml`:
809
+
810
+ ```yaml
811
+ inherit_gem:
812
+ pundit: config/rubocop-rspec.yml
813
+ ```
814
+
603
815
  # External Resources
604
816
 
605
817
  - [RailsApps Example Application: Pundit and Devise](https://github.com/RailsApps/rails-devise-pundit)
606
818
  - [Migrating to Pundit from CanCan](http://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/)
607
819
  - [Testing Pundit Policies with RSpec](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/)
608
- - [Using Pundit outside of a Rails controller](https://github.com/elabs/pundit/pull/136)
820
+ - [Testing Pundit with Minitest](https://github.com/varvet/pundit/issues/204#issuecomment-60166450)
821
+ - [Using Pundit outside of a Rails controller](https://github.com/varvet/pundit/pull/136)
609
822
  - [Straightforward Rails Authorization with Pundit](http://www.sitepoint.com/straightforward-rails-authorization-with-pundit/)
610
823
 
824
+ ## Other implementations
825
+
826
+ - [Flask-Pundit](https://github.com/anurag90x/flask-pundit) (Python) is a [Flask](http://flask.pocoo.org/) extension "heavily inspired by" Pundit
827
+
611
828
  # License
612
829
 
613
830
  Licensed under the MIT license, see the separate LICENSE.txt file.
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rubygems"
2
4
  require "bundler/gem_tasks"
3
5
  require "rspec/core/rake_task"
@@ -16,4 +18,3 @@ YARD::Rake::YardocTask.new do |t|
16
18
  end
17
19
 
18
20
  task default: :spec
19
- task default: :rubocop unless RUBY_ENGINE == "rbx"
@@ -0,0 +1,5 @@
1
+ RSpec:
2
+ Language:
3
+ ExampleGroups:
4
+ Regular:
5
+ - permissions
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Pundit
2
4
  module Generators
3
5
  class InstallGenerator < ::Rails::Generators::Base
4
- source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
6
+ source_root File.expand_path("templates", __dir__)
5
7
 
6
8
  def copy_application_policy
7
- template 'application_policy.rb', 'app/policies/application_policy.rb'
9
+ template "application_policy.rb", "app/policies/application_policy.rb"
8
10
  end
9
11
  end
10
12
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ApplicationPolicy
2
4
  attr_reader :user, :record
3
5
 
@@ -11,7 +13,7 @@ class ApplicationPolicy
11
13
  end
12
14
 
13
15
  def show?
14
- scope.where(:id => record.id).exists?
16
+ false
15
17
  end
16
18
 
17
19
  def create?
@@ -34,20 +36,18 @@ class ApplicationPolicy
34
36
  false
35
37
  end
36
38
 
37
- def scope
38
- Pundit.policy_scope!(user, record.class)
39
- end
40
-
41
39
  class Scope
42
- attr_reader :user, :scope
43
-
44
40
  def initialize(user, scope)
45
41
  @user = user
46
42
  @scope = scope
47
43
  end
48
44
 
49
45
  def resolve
50
- scope
46
+ raise NotImplementedError, "You must define #resolve in #{self.class}"
51
47
  end
48
+
49
+ private
50
+
51
+ attr_reader :user, :scope
52
52
  end
53
53
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Pundit
2
4
  module Generators
3
5
  class PolicyGenerator < ::Rails::Generators::NamedBase
4
- source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
6
+ source_root File.expand_path("templates", __dir__)
5
7
 
6
8
  def create_policy
7
- template 'policy.rb', File.join('app/policies', class_path, "#{file_name}_policy.rb")
9
+ template "policy.rb", File.join("app/policies", class_path, "#{file_name}_policy.rb")
8
10
  end
9
11
 
10
12
  hook_for :test_framework