controller_policies 0.1.0 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db99c9c096c0c752d9d035f928f7c92e9f6efff716975d2e4672b3c18443b16a
4
- data.tar.gz: 01a131a24ad0f546ada81e5d10c1d27564591147c09004a97e6691150d18be71
3
+ metadata.gz: 77ea62355c4991dfc6d3aa1da19d75bbb231e170c6451ed11cc43cb38d53f158
4
+ data.tar.gz: be3d3097f5385f681016c8fd7ee415fc3a6fbdf21acc1320ce6d8891c4f723d7
5
5
  SHA512:
6
- metadata.gz: 05ebbc1bad897b0b6fecf8280f625a5f4d73013255c0dee1e7ab5a6e564fc9aedd21772b9b0bd27d159cf698e09377b3b829dcf5ee60584c95a250841536a336
7
- data.tar.gz: 5e23aa2064c53ea42acea98b1bffaa89767558e4fe2a7a7938b2331b258f0dc0c661f1b8542d866cacf44ec453a222e34019b0c8b7e1b77e1091be89281b84bd
6
+ metadata.gz: 289d8b06bca9542f79799779f2fba6444434ce41b85725e0c89cea6a182f5add24c5a32dbfbd9ed52aae4607cd36c9cd830db4b780fecf050075d1c15b94bd4a
7
+ data.tar.gz: 0d06f4170f6d708f487ce08e4533b93aaaac9916e342fa7a58eaeae3a86be0fde188459ea2299819cc6cc4c553402fc8d80373a00d2c98a3136f6a86ffc3513d
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  Add this line to your application's Gemfile:
6
6
 
7
7
  ```ruby
8
- gem 'controller_policies', '~> 0.1'
8
+ gem 'controller_policies', '~> 1.0'
9
9
  ```
10
10
 
11
11
  ## Usage
@@ -20,7 +20,7 @@ rails g policy_definition my/namespace
20
20
 
21
21
  This will generate a file: `app/policies/my/namespace/definitions.rb`
22
22
 
23
- The developer should edit this file and add the policies for the app.
23
+ The developer should edit this file and add the policies for the app. **It is important to note that the location of the definitions file should reflect the namespace of the associated controllers.**
24
24
 
25
25
  ### `actions` key
26
26
 
@@ -29,13 +29,15 @@ The `actions` key is an array of strings that contain a list of supported contro
29
29
  For example, you have this definition:
30
30
 
31
31
  ```ruby
32
- module Base
33
- DEFINITIONS = {
34
- code: 'policy_code',
35
- name: 'Policy Name',
36
- description: 'I am a policy.',
37
- actions: ['feature_app/users', 'data_app/products#index', 'subscriptions']
38
- }
32
+ module Policies
33
+ module Base
34
+ DEFINITIONS = {
35
+ code: 'policy_code',
36
+ name: 'Policy Name',
37
+ description: 'I am a policy.',
38
+ actions: ['feature_app/users', 'data_app/products#index', 'subscriptions']
39
+ }
40
+ end
39
41
  end
40
42
  ```
41
43
 
@@ -61,7 +63,7 @@ Simply add the line `has_enforced_policies`, and pass a block with one argument
61
63
  ```ruby
62
64
  class MyController < ApplicationController
63
65
  has_enforced_policies do |ability_code|
64
- current_user.abilities.include? ability_code
66
+ render 'unauthorized' unless current_user.abilities.include? ability_code
65
67
  end
66
68
 
67
69
  # ...
@@ -73,14 +75,28 @@ class MyController < ApplicationController
73
75
  has_enforced_policies
74
76
 
75
77
  def ability?(ability_code)
76
- current_user.abilities.include? ability_code
78
+ render 'unauthorized' unless current_user.abilities.include? ability_code
77
79
  end
78
80
  # ...
79
81
  end
80
82
  ```
81
83
 
84
+ It is recommended to use `render` or `redirect_to` within this block **to prevent the controllers from executing the action** when the ability did not exist in the data. The ability checking is done in a `before_action` callback, hence using `render` or `redirect_to` will stop further controller actions. This is a Rails behavior.
85
+
82
86
  Since storing abilities are very flexible and there are truly infinite ways of doing it, *this gem did not support that feature.* Instead, the developer must define their own ability checking.
83
87
 
88
+ ## Skipping Policy Enforcement in Certain Actions
89
+
90
+ There might be an event where there is a need to skip automatic policy enforcements in certain actions. As explained above, the policy enforcement is done in a `before_action` callback. To skip a policy enforcement, simply use the `skip_before_action :check_abilities_by_definition` method from Rails. The `:only` and `:except` options are also available to filter actions.
91
+
92
+ ```ruby
93
+ class MyOtherController < MyController
94
+ skip_before_action :check_abilities_by_definition, only: [:new, :edit]
95
+
96
+ # ...
97
+ end
98
+ ```
99
+
84
100
  ## Ability
85
101
 
86
102
  The Ability class is a model for abilities that come from the definition files.
@@ -91,25 +107,37 @@ The Ability class is a model for abilities that come from the definition files.
91
107
 
92
108
  Get all abilities from all definitions.
93
109
 
110
+ ```ruby
111
+ Ability.all
112
+ ```
113
+
94
114
  #### #all_codes
95
115
 
96
116
  Get all ability codes from all definitions.
97
117
 
98
- #### #where(query)
118
+ ```ruby
119
+ Ability.all_codes
120
+ ```
99
121
 
100
- Filter abilities based on namespace. `query` can be a String, Module or Class.
122
+ #### #where(*queries)
101
123
 
102
- #### #find(query)
124
+ Filter abilities based on namespace. `queries` can be an array of Strings, Modules or Classes.
103
125
 
104
- Find an ability within a namespace. `query` can be a String, Module or Class.
126
+ ```ruby
127
+ Ability.where(Policies::FeatureOne, Policies::FeatureTwo, Policies::FeatureOne::SubFeatureA)
128
+ ```
129
+
130
+ ```ruby
131
+ Ability.where('/feature_one', '/feature_two', '/feature_one/sub_feature_a')
132
+ ```
105
133
 
106
134
  #### #match(expression)
107
135
 
108
136
  Match abilities based on a matching string or regex. The matcher is based on the namespace. `expression` can be a Regexp or String.
109
137
 
110
- #### #mill(expression)
111
-
112
- Find an ability based on a matching string or regex. The matcher is based on the namespace. `expression` can be a Regexp or String.
138
+ ```ruby
139
+ Ability.match(/Policies::FeatureOne(::)?(.)*/)
140
+ ```
113
141
 
114
142
  ### Instance Methods
115
143
 
@@ -117,18 +145,34 @@ Find an ability based on a matching string or regex. The matcher is based on the
117
145
 
118
146
  The code of the ability.
119
147
 
148
+ ```ruby
149
+ ability.code
150
+ ```
151
+
120
152
  #### #name
121
153
 
122
154
  The name of the ability.
123
155
 
156
+ ```ruby
157
+ ability.name
158
+ ```
159
+
124
160
  #### #description
125
161
 
126
162
  The description of the ability.
127
163
 
164
+ ```ruby
165
+ ability.description
166
+ ```
167
+
128
168
  #### #actions
129
169
 
130
170
  Controller actions that the ability can check against.
131
171
 
172
+ ```ruby
173
+ ability.actions
174
+ ```
175
+
132
176
  ## Contributing
133
177
 
134
178
  Bug reports and pull requests are welcome on GitHub at https://github.com/tieeeeen1994/controller_policies. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/tieeeeen1994/controller_policies/blob/master/CODE_OF_CONDUCT.md).
data/lib/ability.rb CHANGED
@@ -33,19 +33,23 @@ class Ability
33
33
  end
34
34
 
35
35
  # Filter abilities based on namespace.
36
- def where(query)
37
- case query.class.to_s
38
- when 'String'
39
- all.select { |ability| ability.namespace.to_s == trim(query).camelize }
40
- when 'Module', 'Class'
41
- all.select { |ability| ability.namespace == query }
36
+ def where(*queries)
37
+ results = []
38
+ queries.each do |query|
39
+ case query.class.to_s
40
+ when 'String'
41
+ results += all.select { |ability| ability.namespace.to_s == "Policies::#{trim(query).camelize}" }
42
+ when 'Module', 'Class'
43
+ results += all.select { |ability| ability.namespace == query }
44
+ end
42
45
  end
46
+ results
43
47
  end
44
48
 
45
49
  # Find an ability within a namespace.
46
- def find(query_string)
47
- where(query_string).first
48
- end
50
+ # def find(query_string)
51
+ # where(query_string).first
52
+ # end
49
53
 
50
54
  # Match abilities based on a matching string or regex. The matcher is based on the namespace.
51
55
  def match(expression)
@@ -56,9 +60,9 @@ class Ability
56
60
  end
57
61
 
58
62
  # Find an ability based on a matching string or regex. The matcher is based on the namespace.
59
- def mill(expression)
60
- match(expression).first
61
- end
63
+ # def mill(expression)
64
+ # match(expression).first
65
+ # end
62
66
 
63
67
  # Path to the policy folder.
64
68
  def policy_path
@@ -78,7 +82,7 @@ class Ability
78
82
  end
79
83
 
80
84
  def definition_files_post_processing(file_path)
81
- module_constant = convert_namespace(file_path)
85
+ module_constant = "Policies::#{convert_namespace(file_path)}".constantize
82
86
  policy_definitions = module_constant::DEFINITIONS
83
87
  policy_definitions.map do |policy_definition|
84
88
  policy_definition[:namespace] = module_constant
@@ -97,7 +101,7 @@ class Ability
97
101
  end
98
102
 
99
103
  def convert_namespace(file_path)
100
- trim(file_path[policy_path.to_s.length..-4].split('/')[0...-1].join('/')).camelize.constantize
104
+ trim(file_path[policy_path.to_s.length..-4].split('/')[0...-1].join('/')).camelize
101
105
  end
102
106
  end
103
107
  end
@@ -10,5 +10,9 @@ module ControllerPolicies
10
10
 
11
11
  define_method(:ability?, &block)
12
12
  end
13
+
14
+ def no_enforced_policies(arguments = {})
15
+ skip_before_action :check_abilities_by_definition, arguments
16
+ end
13
17
  end
14
18
  end
@@ -19,10 +19,10 @@ module ControllerPolicies
19
19
 
20
20
  initializer 'controller_policies.autoloaders' do
21
21
  Rails.autoloaders.each do |autoloader|
22
- autoloader.ignore(Rails.root.join('app/policies'))
22
+ autoloader.ignore(Ability.policy_path)
23
23
  end
24
24
 
25
- Dir[Rails.root.join('app/policies/**/*.rb')].each { |definition| require definition }
25
+ Dir[Ability.policy_path.join('**/*.rb')].each { |definition| require definition }
26
26
  end
27
27
  end
28
28
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ControllerPolicies
4
- VERSION = '0.1.0'
4
+ VERSION = '1.0.0'
5
5
  end
@@ -1,22 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module <%= name.camelize %>
4
- DEFINITIONS = [
5
- {
6
- # Used as identifier for the policy.
7
- code: 'Policy-Code',
8
- # Readable name for the policy.
9
- name: 'Readable Policy Name',
10
- # Readable description for the policy.
11
- description: 'Short description of what this policy allows',
12
- # Controller actions the policy applies to. It works as matchers based on routes.
13
- # It can be empty for manual policy checking.
14
- actions: ['feature_app/users', 'data_app/products#index', 'subscriptions']
15
- },
16
- {
17
- code: 'Another-Policy-Code',
18
- name: 'Another Policy',
19
- description: 'Long description.',
20
- }
21
- ].freeze
3
+ module Policies
4
+ module <%= name.camelize %>
5
+ DEFINITIONS = [
6
+ {
7
+ # Used as identifier for the policy.
8
+ code: 'Policy-Code',
9
+ # Readable name for the policy.
10
+ name: 'Readable Policy Name',
11
+ # Readable description for the policy.
12
+ description: 'Short description of what this policy allows',
13
+ # Controller actions the policy applies to. It works as matchers based on routes.
14
+ # It can be empty for manual policy checking.
15
+ actions: ['feature_app/users', 'data_app/products#index', 'subscriptions']
16
+ },
17
+ {
18
+ code: 'Another-Policy-Code',
19
+ name: 'Another Policy',
20
+ description: 'Long description.',
21
+ }
22
+ ].freeze
23
+ end
22
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: controller_policies
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tien
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-12 00:00:00.000000000 Z
11
+ date: 2024-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -65,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
65
  - !ruby/object:Gem::Version
66
66
  version: '0'
67
67
  requirements: []
68
- rubygems_version: 3.5.3
68
+ rubygems_version: 3.5.11
69
69
  signing_key:
70
70
  specification_version: 4
71
71
  summary: Allows the developer to define policies for controllers.