pundit 2.1.0 → 2.5.0

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +26 -0
  4. data/.github/PULL_REQUEST_TEMPLATE/gem_release_template.md +8 -0
  5. data/.github/pull_request_template.md +9 -0
  6. data/.github/workflows/main.yml +147 -0
  7. data/.github/workflows/push_gem.yml +33 -0
  8. data/.gitignore +1 -0
  9. data/.rubocop.yml +26 -29
  10. data/.rubocop_ignore_git.yml +7 -0
  11. data/.yardopts +1 -1
  12. data/CHANGELOG.md +120 -21
  13. data/CODE_OF_CONDUCT.md +1 -1
  14. data/CONTRIBUTING.md +3 -5
  15. data/Gemfile +23 -2
  16. data/README.md +175 -78
  17. data/Rakefile +1 -0
  18. data/SECURITY.md +19 -0
  19. data/config/rubocop-rspec.yml +5 -0
  20. data/lib/generators/pundit/install/install_generator.rb +6 -2
  21. data/lib/generators/pundit/install/templates/{application_policy.rb → application_policy.rb.tt} +7 -3
  22. data/lib/generators/pundit/policy/policy_generator.rb +6 -2
  23. data/lib/generators/pundit/policy/templates/policy.rb.tt +16 -0
  24. data/lib/generators/rspec/policy_generator.rb +7 -2
  25. data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +1 -1
  26. data/lib/generators/test_unit/policy_generator.rb +7 -2
  27. data/lib/pundit/authorization.rb +251 -0
  28. data/lib/pundit/cache_store/legacy_store.rb +24 -0
  29. data/lib/pundit/cache_store/null_store.rb +27 -0
  30. data/lib/pundit/cache_store.rb +22 -0
  31. data/lib/pundit/context.rb +177 -0
  32. data/lib/pundit/policy_finder.rb +24 -3
  33. data/lib/pundit/railtie.rb +19 -0
  34. data/lib/pundit/rspec.rb +93 -20
  35. data/lib/pundit/version.rb +2 -1
  36. data/lib/pundit.rb +68 -257
  37. data/pundit.gemspec +10 -10
  38. data/spec/authorization_spec.rb +331 -0
  39. data/spec/generators_spec.rb +43 -0
  40. data/spec/policies/post_policy_spec.rb +28 -1
  41. data/spec/policy_finder_spec.rb +84 -17
  42. data/spec/pundit/helper_spec.rb +18 -0
  43. data/spec/pundit_spec.rb +110 -233
  44. data/spec/rspec_dsl_spec.rb +81 -0
  45. data/spec/simple_cov_check_action_formatter.rb +79 -0
  46. data/spec/spec_helper.rb +29 -265
  47. data/spec/support/lib/controller.rb +38 -0
  48. data/spec/support/lib/custom_cache.rb +19 -0
  49. data/spec/support/lib/instance_tracking.rb +20 -0
  50. data/spec/support/models/article.rb +4 -0
  51. data/spec/support/models/article_tag.rb +7 -0
  52. data/spec/support/models/artificial_blog.rb +7 -0
  53. data/spec/support/models/blog.rb +4 -0
  54. data/spec/support/models/comment.rb +5 -0
  55. data/spec/support/models/comment_four_five_six.rb +5 -0
  56. data/spec/support/models/comment_scope.rb +13 -0
  57. data/spec/support/models/comments_relation.rb +15 -0
  58. data/spec/support/models/customer/post.rb +11 -0
  59. data/spec/support/models/default_scope_contains_error.rb +5 -0
  60. data/spec/support/models/dummy_current_user.rb +7 -0
  61. data/spec/support/models/foo.rb +4 -0
  62. data/spec/support/models/post.rb +25 -0
  63. data/spec/support/models/post_four_five_six.rb +9 -0
  64. data/spec/support/models/project_one_two_three/avatar_four_five_six.rb +7 -0
  65. data/spec/support/models/project_one_two_three/tag_four_five_six.rb +11 -0
  66. data/spec/support/models/wiki.rb +4 -0
  67. data/spec/support/policies/article_tag_other_name_policy.rb +13 -0
  68. data/spec/support/policies/base_policy.rb +23 -0
  69. data/spec/support/policies/blog_policy.rb +5 -0
  70. data/spec/support/policies/comment_policy.rb +11 -0
  71. data/spec/support/policies/criteria_policy.rb +5 -0
  72. data/spec/support/policies/default_scope_contains_error_policy.rb +10 -0
  73. data/spec/support/policies/denier_policy.rb +7 -0
  74. data/spec/support/policies/dummy_current_user_policy.rb +9 -0
  75. data/spec/support/policies/nil_class_policy.rb +17 -0
  76. data/spec/support/policies/post_policy.rb +36 -0
  77. data/spec/support/policies/project/admin/comment_policy.rb +15 -0
  78. data/spec/support/policies/project/comment_policy.rb +17 -0
  79. data/spec/support/policies/project/criteria_policy.rb +7 -0
  80. data/spec/support/policies/project/post_policy.rb +13 -0
  81. data/spec/support/policies/project_one_two_three/avatar_four_five_six_policy.rb +6 -0
  82. data/spec/support/policies/project_one_two_three/comment_four_five_six_policy.rb +6 -0
  83. data/spec/support/policies/project_one_two_three/criteria_four_five_six_policy.rb +6 -0
  84. data/spec/support/policies/project_one_two_three/post_four_five_six_policy.rb +6 -0
  85. data/spec/support/policies/project_one_two_three/tag_four_five_six_policy.rb +6 -0
  86. data/spec/support/policies/publication_policy.rb +13 -0
  87. data/spec/support/policies/wiki_policy.rb +8 -0
  88. metadata +80 -130
  89. data/.travis.yml +0 -21
  90. data/lib/generators/pundit/policy/templates/policy.rb +0 -9
  91. /data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
data/lib/pundit/rspec.rb CHANGED
@@ -1,12 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Array#to_sentence
3
4
  require "active_support/core_ext/array/conversions"
4
5
 
5
6
  module Pundit
7
+ # Namespace for Pundit's RSpec integration.
6
8
  module RSpec
9
+ # Namespace for Pundit's RSpec matchers.
7
10
  module Matchers
8
11
  extend ::RSpec::Matchers::DSL
9
12
 
13
+ # @!method description=(description)
14
+ class << self
15
+ # Used to build a suitable description for the Pundit `permit` matcher.
16
+ # @api public
17
+ # @param value [String, Proc]
18
+ # @example
19
+ # Pundit::RSpec::Matchers.description = ->(user, record) do
20
+ # "permit user with role #{user.role} to access record with ID #{record.id}"
21
+ # end
22
+ attr_writer :description
23
+
24
+ # Used to retrieve a suitable description for the Pundit `permit` matcher.
25
+ # @api private
26
+ # @private
27
+ def description(user, record)
28
+ return @description.call(user, record) if defined?(@description) && @description.respond_to?(:call)
29
+
30
+ @description
31
+ end
32
+ end
33
+
10
34
  # rubocop:disable Metrics/BlockLength
11
35
  matcher :permit do |user, record|
12
36
  match_proc = lambda do |policy|
@@ -24,15 +48,25 @@ module Pundit
24
48
  end
25
49
 
26
50
  failure_message_proc = lambda do |policy|
27
- was_were = @violating_permissions.count > 1 ? "were" : "was"
28
51
  "Expected #{policy} to grant #{permissions.to_sentence} on " \
29
- "#{record} but #{@violating_permissions.to_sentence} #{was_were} not granted"
52
+ "#{record} but #{@violating_permissions.to_sentence} #{was_or_were} not granted"
30
53
  end
31
54
 
32
55
  failure_message_when_negated_proc = lambda do |policy|
33
- was_were = @violating_permissions.count > 1 ? "were" : "was"
34
56
  "Expected #{policy} not to grant #{permissions.to_sentence} on " \
35
- "#{record} but #{@violating_permissions.to_sentence} #{was_were} granted"
57
+ "#{record} but #{@violating_permissions.to_sentence} #{was_or_were} granted"
58
+ end
59
+
60
+ def was_or_were
61
+ if @violating_permissions.count > 1
62
+ "were"
63
+ else
64
+ "was"
65
+ end
66
+ end
67
+
68
+ description do
69
+ Pundit::RSpec::Matchers.description(user, record) || super()
36
70
  end
37
71
 
38
72
  if respond_to?(:match_when_negated)
@@ -41,26 +75,73 @@ module Pundit
41
75
  failure_message(&failure_message_proc)
42
76
  failure_message_when_negated(&failure_message_when_negated_proc)
43
77
  else
78
+ # :nocov:
79
+ # Compatibility with RSpec < 3.0, released 2014-06-01.
44
80
  match_for_should(&match_proc)
45
81
  match_for_should_not(&match_when_negated_proc)
46
82
  failure_message_for_should(&failure_message_proc)
47
83
  failure_message_for_should_not(&failure_message_when_negated_proc)
84
+ # :nocov:
85
+ end
86
+
87
+ if ::RSpec.respond_to?(:current_example)
88
+ def current_example
89
+ ::RSpec.current_example
90
+ end
91
+ else
92
+ # :nocov:
93
+ # Compatibility with RSpec < 3.0, released 2014-06-01.
94
+ def current_example
95
+ example
96
+ end
97
+ # :nocov:
48
98
  end
49
99
 
50
100
  def permissions
51
- current_example = ::RSpec.respond_to?(:current_example) ? ::RSpec.current_example : example
52
- current_example.metadata[:permissions]
101
+ current_example.metadata.fetch(:permissions) do
102
+ raise KeyError, <<~ERROR.strip
103
+ No permissions in example metadata, did you forget to wrap with `permissions :show?, ...`?
104
+ ERROR
105
+ end
53
106
  end
54
107
  end
55
108
  # rubocop:enable Metrics/BlockLength
56
109
  end
57
110
 
111
+ # Mixed in to all policy example groups to provide a DSL.
58
112
  module DSL
113
+ # @example
114
+ # describe PostPolicy do
115
+ # permissions :show?, :update? do
116
+ # it { is_expected.to permit(user, own_post) }
117
+ # end
118
+ # end
119
+ #
120
+ # @example focused example group
121
+ # describe PostPolicy do
122
+ # permissions :show?, :update?, :focus do
123
+ # it { is_expected.to permit(user, own_post) }
124
+ # end
125
+ # end
126
+ #
127
+ # @param list [Symbol, Array<Symbol>] a permission to describe
128
+ # @return [void]
59
129
  def permissions(*list, &block)
60
- describe(list.to_sentence, permissions: list, caller: caller) { instance_eval(&block) }
130
+ metadata = { permissions: list, caller: caller }
131
+
132
+ if list.last == :focus
133
+ list.pop
134
+ metadata[:focus] = true
135
+ end
136
+
137
+ description = list.to_sentence
138
+ describe(description, metadata) { instance_eval(&block) }
61
139
  end
62
140
  end
63
141
 
142
+ # Mixed in to all policy example groups.
143
+ #
144
+ # @private not useful
64
145
  module PolicyExampleGroup
65
146
  include Pundit::RSpec::Matchers
66
147
 
@@ -74,17 +155,9 @@ module Pundit
74
155
  end
75
156
 
76
157
  RSpec.configure do |config|
77
- if RSpec::Core::Version::STRING.split(".").first.to_i >= 3
78
- config.include(
79
- Pundit::RSpec::PolicyExampleGroup,
80
- type: :policy,
81
- file_path: %r{spec/policies}
82
- )
83
- else
84
- config.include(
85
- Pundit::RSpec::PolicyExampleGroup,
86
- type: :policy,
87
- example_group: { file_path: %r{spec/policies} }
88
- )
89
- end
158
+ config.include(
159
+ Pundit::RSpec::PolicyExampleGroup,
160
+ type: :policy,
161
+ file_path: %r{spec/policies}
162
+ )
90
163
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pundit
4
- VERSION = "2.1.0".freeze
4
+ # The current version of Pundit.
5
+ VERSION = "2.5.0"
5
6
  end
data/lib/pundit.rb CHANGED
@@ -1,29 +1,53 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support"
4
+
3
5
  require "pundit/version"
4
6
  require "pundit/policy_finder"
5
- require "active_support/concern"
6
- require "active_support/core_ext/string/inflections"
7
- require "active_support/core_ext/object/blank"
8
- require "active_support/core_ext/module/introspection"
9
- require "active_support/dependencies/autoload"
7
+ require "pundit/authorization"
8
+ require "pundit/context"
9
+ require "pundit/cache_store"
10
+ require "pundit/cache_store/null_store"
11
+ require "pundit/cache_store/legacy_store"
12
+ require "pundit/railtie" if defined?(Rails)
10
13
 
11
14
  # @api private
12
15
  # To avoid name clashes with common Error naming when mixing in Pundit,
13
16
  # keep it here with compact class style definition.
14
17
  class Pundit::Error < StandardError; end # rubocop:disable Style/ClassAndModuleChildren
15
18
 
19
+ # Hello? Yes, this is Pundit.
20
+ #
16
21
  # @api public
17
22
  module Pundit
18
- SUFFIX = "Policy".freeze
23
+ # @api private
24
+ # @deprecated See {Pundit::PolicyFinder}
25
+ SUFFIX = Pundit::PolicyFinder::SUFFIX
19
26
 
20
27
  # @api private
28
+ # @private
21
29
  module Generators; end
22
30
 
23
31
  # Error that will be raised when authorization has failed
24
32
  class NotAuthorizedError < Error
25
- attr_reader :query, :record, :policy
26
-
33
+ # @see #initialize
34
+ attr_reader :query
35
+ # @see #initialize
36
+ attr_reader :record
37
+ # @see #initialize
38
+ attr_reader :policy
39
+
40
+ # @overload initialize(message)
41
+ # Create an error with a simple error message.
42
+ # @param [String] message A simple error message string.
43
+ #
44
+ # @overload initialize(options)
45
+ # Create an error with the specified attributes.
46
+ # @param [Hash] options The error options.
47
+ # @option options [String] :message Optional custom error message. Will default to a generalized message.
48
+ # @option options [Symbol] :query The name of the policy method that was checked.
49
+ # @option options [Object] :record The object that was being checked with the policy.
50
+ # @option options [Class] :policy The class of policy that was used for the check.
27
51
  def initialize(options = {})
28
52
  if options.is_a? String
29
53
  message = options
@@ -32,7 +56,10 @@ module Pundit
32
56
  @record = options[:record]
33
57
  @policy = options[:policy]
34
58
 
35
- message = options.fetch(:message) { "not allowed to #{query} this #{record.class}" }
59
+ message = options.fetch(:message) do
60
+ record_name = record.is_a?(Class) ? record.to_s : "this #{record.class}"
61
+ "not allowed to #{policy.class}##{query} #{record_name}"
62
+ end
36
63
  end
37
64
 
38
65
  super(message)
@@ -53,273 +80,57 @@ module Pundit
53
80
  # Error that will be raised if a policy or policy scope is not defined.
54
81
  class NotDefinedError < Error; end
55
82
 
56
- extend ActiveSupport::Concern
83
+ def self.included(base)
84
+ location = caller_locations(1, 1).first
85
+ warn <<~WARNING
86
+ 'include Pundit' is deprecated. Please use 'include Pundit::Authorization' instead.
87
+ (called from #{location.label} at #{location.path}:#{location.lineno})
88
+ WARNING
89
+ base.include Authorization
90
+ end
57
91
 
58
92
  class << self
59
- # Retrieves the policy for the given record, initializing it with the
60
- # record and user and finally throwing an error if the user is not
61
- # authorized to perform the given action.
62
- #
63
- # @param user [Object] the user that initiated the action
64
- # @param record [Object] the object we're checking permissions of
65
- # @param query [Symbol, String] the predicate method to check on the policy (e.g. `:show?`)
66
- # @param policy_class [Class] the policy class we want to force use of
67
- # @raise [NotAuthorizedError] if the given query method returned false
68
- # @return [Object] Always returns the passed object record
69
- def authorize(user, record, query, policy_class: nil)
70
- policy = policy_class ? policy_class.new(user, record) : policy!(user, record)
71
-
72
- raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
73
-
74
- record
75
- end
76
-
77
- # Retrieves the policy scope for the given record.
78
- #
79
- # @see https://github.com/varvet/pundit#scopes
80
- # @param user [Object] the user that initiated the action
81
- # @param scope [Object] the object we're retrieving the policy scope for
82
- # @raise [InvalidConstructorError] if the policy constructor called incorrectly
83
- # @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
84
- def policy_scope(user, scope)
85
- policy_scope_class = PolicyFinder.new(scope).scope
86
- return unless policy_scope_class
87
-
88
- begin
89
- policy_scope = policy_scope_class.new(user, pundit_model(scope))
90
- rescue ArgumentError
91
- raise InvalidConstructorError, "Invalid #<#{policy_scope_class}> constructor is called"
93
+ # @see Pundit::Context#authorize
94
+ def authorize(user, record, query, policy_class: nil, cache: nil)
95
+ context = if cache
96
+ policy_cache = CacheStore::LegacyStore.new(cache)
97
+ Context.new(user: user, policy_cache: policy_cache)
98
+ else
99
+ Context.new(user: user)
92
100
  end
93
101
 
94
- policy_scope.resolve
102
+ context.authorize(record, query: query, policy_class: policy_class)
95
103
  end
96
104
 
97
- # Retrieves the policy scope for the given record.
98
- #
99
- # @see https://github.com/varvet/pundit#scopes
100
- # @param user [Object] the user that initiated the action
101
- # @param scope [Object] the object we're retrieving the policy scope for
102
- # @raise [NotDefinedError] if the policy scope cannot be found
103
- # @raise [InvalidConstructorError] if the policy constructor called incorrectly
104
- # @return [Scope{#resolve}] instance of scope class which can resolve to a scope
105
- def policy_scope!(user, scope)
106
- policy_scope_class = PolicyFinder.new(scope).scope!
107
- return unless policy_scope_class
108
-
109
- begin
110
- policy_scope = policy_scope_class.new(user, pundit_model(scope))
111
- rescue ArgumentError
112
- raise InvalidConstructorError, "Invalid #<#{policy_scope_class}> constructor is called"
113
- end
114
-
115
- policy_scope.resolve
105
+ # @see Pundit::Context#policy_scope
106
+ def policy_scope(user, *args, **kwargs, &block)
107
+ Context.new(user: user).policy_scope(*args, **kwargs, &block)
116
108
  end
117
109
 
118
- # Retrieves the policy for the given record.
119
- #
120
- # @see https://github.com/varvet/pundit#policies
121
- # @param user [Object] the user that initiated the action
122
- # @param record [Object] the object we're retrieving the policy for
123
- # @raise [InvalidConstructorError] if the policy constructor called incorrectly
124
- # @return [Object, nil] instance of policy class with query methods
125
- def policy(user, record)
126
- policy = PolicyFinder.new(record).policy
127
- policy.new(user, pundit_model(record)) if policy
128
- rescue ArgumentError
129
- raise InvalidConstructorError, "Invalid #<#{policy}> constructor is called"
110
+ # @see Pundit::Context#policy_scope!
111
+ def policy_scope!(user, *args, **kwargs, &block)
112
+ Context.new(user: user).policy_scope!(*args, **kwargs, &block)
130
113
  end
131
114
 
132
- # Retrieves the policy for the given record.
133
- #
134
- # @see https://github.com/varvet/pundit#policies
135
- # @param user [Object] the user that initiated the action
136
- # @param record [Object] the object we're retrieving the policy for
137
- # @raise [NotDefinedError] if the policy cannot be found
138
- # @raise [InvalidConstructorError] if the policy constructor called incorrectly
139
- # @return [Object] instance of policy class with query methods
140
- def policy!(user, record)
141
- policy = PolicyFinder.new(record).policy!
142
- policy.new(user, pundit_model(record))
143
- rescue ArgumentError
144
- raise InvalidConstructorError, "Invalid #<#{policy}> constructor is called"
115
+ # @see Pundit::Context#policy
116
+ def policy(user, *args, **kwargs, &block)
117
+ Context.new(user: user).policy(*args, **kwargs, &block)
145
118
  end
146
119
 
147
- private
148
-
149
- def pundit_model(record)
150
- record.is_a?(Array) ? record.last : record
120
+ # @see Pundit::Context#policy!
121
+ def policy!(user, *args, **kwargs, &block)
122
+ Context.new(user: user).policy!(*args, **kwargs, &block)
151
123
  end
152
124
  end
153
125
 
126
+ # Rails view helpers, to allow a slightly different view-specific
127
+ # implementation of the methods in {Pundit::Authorization}.
128
+ #
154
129
  # @api private
155
130
  module Helper
131
+ # @see Pundit::Authorization#pundit_policy_scope
156
132
  def policy_scope(scope)
157
133
  pundit_policy_scope(scope)
158
134
  end
159
135
  end
160
-
161
- included do
162
- helper Helper if respond_to?(:helper)
163
- if respond_to?(:helper_method)
164
- helper_method :policy
165
- helper_method :pundit_policy_scope
166
- helper_method :pundit_user
167
- end
168
- end
169
-
170
- protected
171
-
172
- # @return [Boolean] whether authorization has been performed, i.e. whether
173
- # one {#authorize} or {#skip_authorization} has been called
174
- def pundit_policy_authorized?
175
- !!@_pundit_policy_authorized
176
- end
177
-
178
- # @return [Boolean] whether policy scoping has been performed, i.e. whether
179
- # one {#policy_scope} or {#skip_policy_scope} has been called
180
- def pundit_policy_scoped?
181
- !!@_pundit_policy_scoped
182
- end
183
-
184
- # Raises an error if authorization has not been performed, usually used as an
185
- # `after_action` filter to prevent programmer error in forgetting to call
186
- # {#authorize} or {#skip_authorization}.
187
- #
188
- # @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
189
- # @raise [AuthorizationNotPerformedError] if authorization has not been performed
190
- # @return [void]
191
- def verify_authorized
192
- raise AuthorizationNotPerformedError, self.class unless pundit_policy_authorized?
193
- end
194
-
195
- # Raises an error if policy scoping has not been performed, usually used as an
196
- # `after_action` filter to prevent programmer error in forgetting to call
197
- # {#policy_scope} or {#skip_policy_scope} in index actions.
198
- #
199
- # @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
200
- # @raise [AuthorizationNotPerformedError] if policy scoping has not been performed
201
- # @return [void]
202
- def verify_policy_scoped
203
- raise PolicyScopingNotPerformedError, self.class unless pundit_policy_scoped?
204
- end
205
-
206
- # Retrieves the policy for the given record, initializing it with the record
207
- # and current user and finally throwing an error if the user is not
208
- # authorized to perform the given action.
209
- #
210
- # @param record [Object] the object we're checking permissions of
211
- # @param query [Symbol, String] the predicate method to check on the policy (e.g. `:show?`).
212
- # If omitted then this defaults to the Rails controller action name.
213
- # @param policy_class [Class] the policy class we want to force use of
214
- # @raise [NotAuthorizedError] if the given query method returned false
215
- # @return [Object] Always returns the passed object record
216
- def authorize(record, query = nil, policy_class: nil)
217
- query ||= "#{action_name}?"
218
-
219
- @_pundit_policy_authorized = true
220
-
221
- policy = policy_class ? policy_class.new(pundit_user, record) : policy(record)
222
-
223
- raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
224
-
225
- record
226
- end
227
-
228
- # Allow this action not to perform authorization.
229
- #
230
- # @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
231
- # @return [void]
232
- def skip_authorization
233
- @_pundit_policy_authorized = true
234
- end
235
-
236
- # Allow this action not to perform policy scoping.
237
- #
238
- # @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
239
- # @return [void]
240
- def skip_policy_scope
241
- @_pundit_policy_scoped = true
242
- end
243
-
244
- # Retrieves the policy scope for the given record.
245
- #
246
- # @see https://github.com/varvet/pundit#scopes
247
- # @param scope [Object] the object we're retrieving the policy scope for
248
- # @param policy_scope_class [Class] the policy scope class we want to force use of
249
- # @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
250
- def policy_scope(scope, policy_scope_class: nil)
251
- @_pundit_policy_scoped = true
252
- policy_scope_class ? policy_scope_class.new(pundit_user, scope).resolve : pundit_policy_scope(scope)
253
- end
254
-
255
- # Retrieves the policy for the given record.
256
- #
257
- # @see https://github.com/varvet/pundit#policies
258
- # @param record [Object] the object we're retrieving the policy for
259
- # @return [Object, nil] instance of policy class with query methods
260
- def policy(record)
261
- policies[record] ||= Pundit.policy!(pundit_user, record)
262
- end
263
-
264
- # Retrieves a set of permitted attributes from the policy by instantiating
265
- # the policy class for the given record and calling `permitted_attributes` on
266
- # it, or `permitted_attributes_for_{action}` if `action` is defined. It then infers
267
- # what key the record should have in the params hash and retrieves the
268
- # permitted attributes from the params hash under that key.
269
- #
270
- # @see https://github.com/varvet/pundit#strong-parameters
271
- # @param record [Object] the object we're retrieving permitted attributes for
272
- # @param action [Symbol, String] the name of the action being performed on the record (e.g. `:update`).
273
- # If omitted then this defaults to the Rails controller action name.
274
- # @return [Hash{String => Object}] the permitted attributes
275
- def permitted_attributes(record, action = action_name)
276
- policy = policy(record)
277
- method_name = if policy.respond_to?("permitted_attributes_for_#{action}")
278
- "permitted_attributes_for_#{action}"
279
- else
280
- "permitted_attributes"
281
- end
282
- pundit_params_for(record).permit(*policy.public_send(method_name))
283
- end
284
-
285
- # Retrieves the params for the given record.
286
- #
287
- # @param record [Object] the object we're retrieving params for
288
- # @return [ActionController::Parameters] the params
289
- def pundit_params_for(record)
290
- params.require(PolicyFinder.new(record).param_key)
291
- end
292
-
293
- # Cache of policies. You should not rely on this method.
294
- #
295
- # @api private
296
- # rubocop:disable Naming/MemoizedInstanceVariableName
297
- def policies
298
- @_pundit_policies ||= {}
299
- end
300
- # rubocop:enable Naming/MemoizedInstanceVariableName
301
-
302
- # Cache of policy scope. You should not rely on this method.
303
- #
304
- # @api private
305
- # rubocop:disable Naming/MemoizedInstanceVariableName
306
- def policy_scopes
307
- @_pundit_policy_scopes ||= {}
308
- end
309
- # rubocop:enable Naming/MemoizedInstanceVariableName
310
-
311
- # Hook method which allows customizing which user is passed to policies and
312
- # scopes initialized by {#authorize}, {#policy} and {#policy_scope}.
313
- #
314
- # @see https://github.com/varvet/pundit#customize-pundit-user
315
- # @return [Object] the user object to be used with pundit
316
- def pundit_user
317
- current_user
318
- end
319
-
320
- private
321
-
322
- def pundit_policy_scope(scope)
323
- policy_scopes[scope] ||= Pundit.policy_scope!(pundit_user, scope)
324
- end
325
136
  end
data/pundit.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
8
8
  gem.name = "pundit"
9
9
  gem.version = Pundit::VERSION
10
10
  gem.authors = ["Jonas Nicklas", "Varvet AB"]
11
- gem.email = ["jonas.nicklas@gmail.com", "dev@elabs.se"]
11
+ gem.email = ["jonas.nicklas@gmail.com", "info@varvet.com"]
12
12
  gem.description = "Object oriented authorization for Rails applications"
13
13
  gem.summary = "OO authorization for Rails"
14
14
  gem.homepage = "https://github.com/varvet/pundit"
@@ -16,16 +16,16 @@ Gem::Specification.new do |gem|
16
16
 
17
17
  gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
18
  gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
19
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
19
  gem.require_paths = ["lib"]
21
20
 
21
+ gem.metadata = {
22
+ "rubygems_mfa_required" => "true",
23
+ "bug_tracker_uri" => "https://github.com/varvet/pundit/issues",
24
+ "changelog_uri" => "https://github.com/varvet/pundit/blob/main/CHANGELOG.md",
25
+ "documentation_uri" => "https://github.com/varvet/pundit/blob/main/README.md",
26
+ "homepage_uri" => "https://github.com/varvet/pundit",
27
+ "source_code_uri" => "https://github.com/varvet/pundit"
28
+ }
29
+
22
30
  gem.add_dependency "activesupport", ">= 3.0.0"
23
- gem.add_development_dependency "actionpack", ">= 3.0.0"
24
- gem.add_development_dependency "activemodel", ">= 3.0.0"
25
- gem.add_development_dependency "bundler"
26
- gem.add_development_dependency "pry"
27
- gem.add_development_dependency "rake"
28
- gem.add_development_dependency "rspec", ">= 2.0.0"
29
- gem.add_development_dependency "rubocop", "0.57.2"
30
- gem.add_development_dependency "yard"
31
31
  end