controller_policies 1.0.1 → 1.1.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: 6bce0f759505e11b5f05fd9d220d1f8553a1b1a281f50a40b51533a160a225fd
4
- data.tar.gz: e5f9d53c8bfe61e53e546c760fe0eba07d298717f5306f99575da4c8f60c4fb5
3
+ metadata.gz: 876b65cbe173231e141e578fd2e650dcbbcbbba02b0ece615c3ddf80395ba96f
4
+ data.tar.gz: bcf69abce9066f2b99fa99d21481ecca033e2408d2ed0ec752f2b5cf080a482f
5
5
  SHA512:
6
- metadata.gz: 2b25df0839fdc02faf866a769f1102175ecda41fbf6e018ea735c981c712354270768af5770dc266cc9fc998cddc0ae6316c90b54570fb5faa4abf06c8c43d8b
7
- data.tar.gz: da0373ebea81108926b63a898b0b9955aff0a9383a2fd4e49d7da0ea67c6784429550edb9d1312c34534a50aa4bc531bc1002f5f606b796431e773fa494f7827
6
+ metadata.gz: 8031665a97f07ab1e47534f38376eb4b5170538ffa9da42bc69d7e6c2de847e855d64acfdc2db32bbe5fbaee6d1f709e4be147fba9912e39c0089d3d72cecd24
7
+ data.tar.gz: 2b30ca3aae95937a5625268853a9caa5697c460f1b24b7cffa5dc8dd875d5dee6005e367fb8029627227f7829b808c5f1485914869159e18e9d6545dccc1682f
data/README.md CHANGED
@@ -20,6 +20,16 @@ rails g policy_definition my/namespace
20
20
 
21
21
  This will generate a file: `app/policies/my/namespace/definitions.rb`
22
22
 
23
+ For controllers without a namespace (root-level controllers), you can generate a root-level definitions file:
24
+
25
+ ```sh
26
+ rails g policy_definition root
27
+ # or simply
28
+ rails g policy_definition
29
+ ```
30
+
31
+ This will generate a file: `app/policies/definitions.rb`
32
+
23
33
  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
34
 
25
35
  ### `actions` key
@@ -43,16 +53,35 @@ end
43
53
 
44
54
  The above definition will have enforced policies on `Base::FeatureApp::UsersController` (all actions), `Base::DataApp::ProductsController` (`index` action) and `Base::SubscriptionController`.
45
55
 
56
+ For root-level controllers (controllers without a namespace), you can define policies directly in the `Policies` module:
57
+
58
+ ```ruby
59
+ module Policies
60
+ DEFINITIONS = [
61
+ {
62
+ code: 'user_management',
63
+ name: 'User Management',
64
+ description: 'Allows user management operations',
65
+ actions: ['users', 'profiles#show', 'dashboard']
66
+ }
67
+ ]
68
+ end
69
+ ```
70
+
71
+ The above definition will have enforced policies on `UsersController` (all actions), `ProfilesController` (`show` action) and `DashboardController`.
72
+
46
73
  **Do note that the `actions` array implement *Regular Expression Matching*. That means that if you have multiple controllers with the same name on their parent namespace, the parent will be matched first.** To avoid this problem, simply add the namespace to match the intended child instead.
47
74
 
48
75
  ```ruby
49
- module Base
50
- DEFINITIONS = {
51
- code: 'policy_code',
52
- name: 'Policy Name',
53
- description: 'I am a policy.',
54
- actions: ['feature_app/users', 'another_base/data_app/products#index', 'base/subscriptions']
55
- }
76
+ module Policies
77
+ module Base
78
+ DEFINITIONS = {
79
+ code: 'policy_code',
80
+ name: 'Policy Name',
81
+ description: 'I am a policy.',
82
+ actions: ['feature_app/users', 'another_base/data_app/products#index', 'base/subscriptions']
83
+ }
84
+ end
56
85
  end
57
86
  ```
58
87
 
data/lib/ability.rb CHANGED
@@ -38,7 +38,12 @@ class Ability
38
38
  queries.each do |query|
39
39
  case query.class.to_s
40
40
  when 'String'
41
- results += all.select { |ability| ability.namespace.to_s == "Policies::#{trim(query).camelize}" }
41
+ # Handle empty string or root namespace
42
+ if query.empty? || query == '/'
43
+ results += all.select { |ability| ability.namespace == Policies }
44
+ else
45
+ results += all.select { |ability| ability.namespace.to_s == "Policies::#{trim(query).camelize}" }
46
+ end
42
47
  when 'Module', 'Class'
43
48
  results += all.select { |ability| ability.namespace == query }
44
49
  end
@@ -82,7 +87,15 @@ class Ability
82
87
  end
83
88
 
84
89
  def definition_files_post_processing(file_path)
85
- module_constant = "Policies::#{convert_namespace(file_path)}".constantize
90
+ namespace_path = convert_namespace(file_path)
91
+
92
+ if namespace_path.empty?
93
+ # Handle root-level definitions.rb file
94
+ module_constant = Policies
95
+ else
96
+ module_constant = "Policies::#{namespace_path}".constantize
97
+ end
98
+
86
99
  policy_definitions = module_constant::DEFINITIONS
87
100
  policy_definitions.map do |policy_definition|
88
101
  policy_definition[:namespace] = module_constant
@@ -34,9 +34,18 @@ module ControllerPolicies
34
34
  # Method that attempts to go through policy definitions and check if it matches the current controller.
35
35
  # If it finds a match, it will be an applicable definition to check abilities for.
36
36
  def applicable_abilities
37
- @applicable_abilities ||= Ability.where(controller_namespace).select do |ability|
38
- matching_actions = ability.actions.select { |action| /#{action}/.match?("#{controller_path}##{action_name}") }
39
- matching_actions.present?
37
+ @applicable_abilities ||= begin
38
+ # Get abilities for the current controller namespace, or root if no namespace
39
+ namespace_abilities = if controller_namespace.empty?
40
+ Ability.where('') # This will get root-level policies
41
+ else
42
+ Ability.where(controller_namespace)
43
+ end
44
+
45
+ namespace_abilities.select do |ability|
46
+ matching_actions = ability.actions.select { |action| /#{action}/.match?("#{controller_path}##{action_name}") }
47
+ matching_actions.present?
48
+ end
40
49
  end
41
50
  end
42
51
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ControllerPolicies
4
- VERSION = '1.0.1'
4
+ VERSION = '1.1.0'
5
5
  end
@@ -3,18 +3,22 @@
3
3
  # Generates a definition file for a namespace.
4
4
  class PolicyDefinitionGenerator < Rails::Generators::Base
5
5
  source_root File.expand_path('templates', __dir__)
6
- desc 'Generates a policy definition file based on given namespace.'
7
- argument :name, type: :string, required: true, desc: 'The namespace for the definition file.'
6
+ desc 'Generates a policy definition file based on given namespace. Leave empty for root-level definitions.'
7
+ argument :name, type: :string, required: false, default: '',
8
+ desc: 'The namespace for the definition file. Leave empty for root-level definitions.'
8
9
 
9
10
  def create_policy_definition_file
10
- return if processed_name.blank?
11
-
12
- template 'definitions.rb', "app/policies/#{processed_name}/definitions.rb"
11
+ if processed_name.blank?
12
+ # Generate root-level definitions.rb
13
+ template 'root_definitions.rb', 'app/policies/definitions.rb'
14
+ else
15
+ template 'modular_definitions.rb', "app/policies/#{processed_name}/definitions.rb"
16
+ end
13
17
  end
14
18
 
15
19
  private
16
20
 
17
21
  def processed_name
18
- @processed_name ||= name.strip.delete_prefix('/').delete_suffix('/')
22
+ @processed_name ||= name.strip.delete_prefix('/').delete_suffix('/') || ''
19
23
  end
20
24
  end
@@ -17,7 +17,7 @@ module Policies
17
17
  {
18
18
  code: 'Another-Policy-Code',
19
19
  name: 'Another Policy',
20
- description: 'Long description.',
20
+ description: 'Long description.'
21
21
  }
22
22
  ].freeze
23
23
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Policies
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: ['users', 'products#index', 'dashboard']
15
+ },
16
+ {
17
+ code: 'Another-Policy-Code',
18
+ name: 'Another Policy',
19
+ description: 'Long description.'
20
+ }
21
+ ].freeze
22
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: controller_policies
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tien
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-03 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -47,7 +47,8 @@ files:
47
47
  - lib/controller_policies/railtie.rb
48
48
  - lib/controller_policies/version.rb
49
49
  - lib/generators/policy_definition_generator.rb
50
- - lib/generators/templates/definitions.rb.tt
50
+ - lib/generators/templates/modular_definitions.rb.tt
51
+ - lib/generators/templates/root_definitions.rb.tt
51
52
  homepage: https://github.com/tieeeeen1994/rails-controller-policies
52
53
  licenses:
53
54
  - MIT
@@ -68,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
69
  - !ruby/object:Gem::Version
69
70
  version: '0'
70
71
  requirements: []
71
- rubygems_version: 3.6.5
72
+ rubygems_version: 3.7.1
72
73
  specification_version: 4
73
74
  summary: Allows the developer to define policies for controllers.
74
75
  test_files: []