rabarber 4.1.4 → 5.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: 5152a05ff663a5216b2fc2f546bf3b111f3e78a4c44c0088e72f2f73ac89464f
4
- data.tar.gz: f6f24ff379055cfd5f4f7e93377a548289fd8f7b30b2f06053fd958f6ab8e5a3
3
+ metadata.gz: 1de40ccff8f5d39718c2c908913c5a67149eeada18598a37b51ec53e900200cc
4
+ data.tar.gz: d9a02594d2c2215499cd2609d57f3fa14e796d9b3df6d0176b5fa1b510cf2d72
5
5
  SHA512:
6
- metadata.gz: e31e2c7fa58d42096203d1f8027acea031a720fafe21fd44b179a8c2e66818686ebd55abf2ec0d3229c93fc7e04b514a68fa20feebef25b7e11048caac4e58e7
7
- data.tar.gz: 6b7143de48cc95ead0caf5256c9e3d28a54a515f4ea50cf33fc87271d5d13071782fad1926dda698e7842047f7bbed4a2cfe8254be3390af0ab1fde2608a9b30
6
+ metadata.gz: e7862b8b5793a4c3076b2e9c34eec91df58b79b629273b7e2fc9a6c97b74d3a42b7ac53bd85bad8ee270549c13a6d8e5d747ea6fe3472b2d72f067aafc247028
7
+ data.tar.gz: a9f1cbf65045fde78aeac07e6217caca037dc1f85e97065e26a07f1c52bfce46deb4e60513617df6572a0883e792dacbf70a18c0f19d14f31e97171420903cc9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## v5.0.0
2
+
3
+ ### Breaking:
4
+
5
+ - Dropped support for Ruby 3.1
6
+ - Dropped support for Rails 7.0
7
+ - Removed the `must_have_roles` configuration option and its associated behavior
8
+ - Completely removed Audit Trail feature
9
+ - Introduced a new `user_model_name` configuration option
10
+ - Added `with_authorization` method for more granular authorization control
11
+ - `Rabarber::Role.rename` and `Rabarber::Role.remove` now require the role to exist
12
+
13
+ To upgrade to v5.0.0, please refer to the [migration guide](https://github.com/brownboxdev/rabarber/discussions/77)
14
+
15
+ ### Features:
16
+
17
+ - Added migration helpers to assist with context renaming and removal
18
+
19
+ ### Bugs:
20
+
21
+ - Fixed an error that occurred when Rabarber was used with eager loading disabled
22
+ - Fixed an issue where authorization rules weren’t cleared on code reload when eager loading was disabled
23
+
24
+ ### Misc:
25
+
26
+ - Optimized various parts of the code and database queries for improved performance
27
+ - Streamlined the authorization process by requiring the user to be authenticated before access is verified
28
+ - Rabarber now skips roles with missing instance context and prunes them automatically; missing class context still raises errors
29
+
1
30
  ## v4.1.4
2
31
 
3
32
  ### Misc:
@@ -86,7 +115,7 @@
86
115
 
87
116
  - Changed Rabarber roles table structure
88
117
 
89
- To upgrade to v3.0.0, please refer to the [migration guide](https://github.com/enjaku4/rabarber/discussions/58)
118
+ To upgrade to v3.0.0, please refer to the [migration guide](https://github.com/brownboxdev/rabarber/discussions/58)
90
119
 
91
120
  ### Features:
92
121
 
@@ -110,7 +139,7 @@ To upgrade to v3.0.0, please refer to the [migration guide](https://github.com/e
110
139
  - Replaced `when_unauthorized` configuration option with an overridable controller method
111
140
  - Renamed `Rabarber::Role.assignees_for` method to `Rabarber::Role.assignees`
112
141
 
113
- To upgrade to v2.0.0, please refer to the [migration guide](https://github.com/enjaku4/rabarber/discussions/52)
142
+ To upgrade to v2.0.0, please refer to the [migration guide](https://github.com/brownboxdev/rabarber/discussions/52)
114
143
 
115
144
  ### Features:
116
145
 
@@ -132,7 +161,7 @@ To upgrade to v2.0.0, please refer to the [migration guide](https://github.com/e
132
161
 
133
162
  - Add 'Audit trail' feature: Logging of role assignments, revocations, and unauthorized access attempts
134
163
  - Add `audit_trail_enabled` configuration option, allowing to enable or disable the audit trail
135
- - Deprecate `when_actions_missing` and `when_roles_missing` configuration options (see [the discussion](https://github.com/enjaku4/rabarber/discussions/48))
164
+ - Deprecate `when_actions_missing` and `when_roles_missing` configuration options
136
165
 
137
166
  ## v1.3.1
138
167
 
data/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # Rabarber: Simplified Authorization for Rails
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rabarber.svg)](http://badge.fury.io/rb/rabarber)
4
- [![Github Actions badge](https://github.com/enjaku4/rabarber/actions/workflows/ci.yml/badge.svg)](https://github.com/enjaku4/rabarber/actions/workflows/ci.yml)
4
+ [![Github Actions badge](https://github.com/brownboxdev/rabarber/actions/workflows/ci.yml/badge.svg)](https://github.com/brownboxdev/rabarber/actions/workflows/ci.yml)
5
5
 
6
- Rabarber is a role-based authorization library for Ruby on Rails. It provides a set of tools for managing user roles and defining authorization rules, supports multi-tenancy and comes with audit logging for enhanced security.
6
+ Rabarber is a role-based authorization library for Ruby on Rails. It provides a set of tools for managing user roles and defining authorization rules, with support for multi-tenancy and fine-grained access control.
7
7
 
8
8
  ---
9
9
 
10
10
  **Example of Usage**:
11
11
 
12
- Consider a CRM system where users with different roles have distinct access levels. For instance, the role `accountant` can interact with invoices but cannot access marketing information, while the role `marketer` has access to marketing-related data. Such authorization rules can be easily defined with Rabarber.
12
+ Consider a CRM system where users with different roles have distinct access levels. For instance, the role `accountant` can interact with invoices but cannot access marketing information, while the role `marketer` has access to marketing-related data. You can define such authorization rules easily with Rabarber.
13
13
 
14
14
  ---
15
15
 
@@ -29,6 +29,7 @@ class TicketsController < ApplicationController
29
29
  end
30
30
  end
31
31
  ```
32
+
32
33
  This means that `admin` users can access everything in `TicketsController`, while `manager` role can access only `index` action.
33
34
 
34
35
  ## Table of Contents
@@ -36,26 +37,27 @@ This means that `admin` users can access everything in `TicketsController`, whil
36
37
  **Gem usage:**
37
38
  - [Installation](#installation)
38
39
  - [Configuration](#configuration)
39
- - [Roles](#roles)
40
+ - [Role Assignments](#role-assignments)
41
+ - [Role Management](#role-management)
40
42
  - [Authorization Rules](#authorization-rules)
41
43
  - [Dynamic Authorization Rules](#dynamic-authorization-rules)
42
44
  - [Context / Multi-tenancy](#context--multi-tenancy)
43
45
  - [When Unauthorized](#when-unauthorized)
44
46
  - [Skip Authorization](#skip-authorization)
45
47
  - [View Helpers](#view-helpers)
46
- - [Audit Trail](#audit-trail)
47
48
 
48
49
  **Community Resources:**
49
50
  - [Problems?](#problems)
50
51
  - [Contributing](#contributing)
51
52
  - [Code of Conduct](#code-of-conduct)
53
+ - [Old Versions](#old-versions)
52
54
 
53
55
  **Legal:**
54
56
  - [License](#license)
55
57
 
56
58
  ## Installation
57
59
 
58
- Add the Rabarber gem to your Gemfile:
60
+ Add Rabarber to your Gemfile:
59
61
 
60
62
  ```rb
61
63
  gem "rabarber"
@@ -67,19 +69,19 @@ Install the gem:
67
69
  bundle install
68
70
  ```
69
71
 
70
- Next, generate a migration to create tables for storing roles in the database. Make sure to specify the table name of the model representing users in your application as an argument. For instance, if the table name is `users`, run:
72
+ Generate a migration to create tables for storing roles. Run the generator with the table name used by the model that represents users in your application. For example, if the table is `users`, run:
71
73
 
72
74
  ```shell
73
75
  rails g rabarber:roles users
74
76
  ```
75
77
 
76
- Rabarber supports UUIDs as primary keys. If your application uses UUIDs, add `--uuid` option to the generator:
78
+ Rabarber supports UUIDs as primary keys. If your application uses UUIDs, add `--uuid` option:
77
79
 
78
80
  ```shell
79
81
  rails g rabarber:roles users --uuid
80
82
  ```
81
83
 
82
- Finally, run the migration to apply the changes to the database:
84
+ Finally, run the migration:
83
85
 
84
86
  ```shell
85
87
  rails db:migrate
@@ -87,34 +89,23 @@ rails db:migrate
87
89
 
88
90
  ## Configuration
89
91
 
90
- If specific customization is required, Rabarber can be configured by using `.configure` method in an initializer:
92
+ If customization is required, Rabarber can be configured using `.configure` method in an initializer:
91
93
 
92
94
  ```rb
93
95
  Rabarber.configure do |config|
94
- config.audit_trail_enabled = true
95
96
  config.cache_enabled = true
96
97
  config.current_user_method = :current_user
97
- config.must_have_roles = false
98
+ config.user_model_name = "User"
98
99
  end
99
100
  ```
100
101
 
101
- - `audit_trail_enabled` determines whether the audit trail functionality is enabled. The audit trail is enabled by default.
102
102
  - `cache_enabled` determines whether roles are cached to avoid unnecessary database queries. Roles are cached by default. If you need to clear the cache, use `Rabarber::Cache.clear` method.
103
- - `current_user_method` represents the method that returns the currently authenticated user. The default value is `:current_user`.
104
- - `must_have_roles` determines whether a user with no roles can access endpoints permitted to everyone. The default value is `false` (allowing users without roles to access such endpoints).
105
-
106
- ## Roles
103
+ - `current_user_method` defines the method used to access the currently authenticated user. Default is `:current_user`.
104
+ - `user_model_name` sets the name of the model representing the user in your application. Default is `"User"`.
107
105
 
108
- Include `Rabarber::HasRoles` module in your model representing users in your application:
109
-
110
- ```rb
111
- class User < ApplicationRecord
112
- include Rabarber::HasRoles
113
- # ...
114
- end
115
- ```
106
+ ## Role Assignments
116
107
 
117
- This adds the following methods:
108
+ Rabarber automatically augments your user model (defined via `user_model_name` configuration) with role-related methods.
118
109
 
119
110
  **`#assign_roles(*roles, context: nil, create_new: true)`**
120
111
 
@@ -123,10 +114,13 @@ To assign roles, use:
123
114
  ```rb
124
115
  user.assign_roles(:accountant, :marketer)
125
116
  ```
126
- By default, it will automatically create any roles that don't exist. If you want to assign only existing roles and prevent the creation of new ones, use the method with `create_new: false` argument:
117
+
118
+ By default, it will automatically create any roles that don't exist. To assign only existing roles and prevent automatic creation, pass `create_new: false`:
119
+
127
120
  ```rb
128
121
  user.assign_roles(:accountant, :marketer, create_new: false)
129
122
  ```
123
+
130
124
  The method returns an array of roles assigned to the user.
131
125
 
132
126
  **`#revoke_roles(*roles, context: nil)`**
@@ -136,7 +130,8 @@ To revoke roles, use:
136
130
  ```rb
137
131
  user.revoke_roles(:accountant, :marketer)
138
132
  ```
139
- If the user doesn't have the role you want to revoke, it will be ignored.
133
+
134
+ Roles the user doesn’t have are ignored.
140
135
 
141
136
  The method returns an array of roles assigned to the user.
142
137
 
@@ -148,7 +143,7 @@ To check whether the user has a role, use:
148
143
  user.has_role?(:accountant, :marketer)
149
144
  ```
150
145
 
151
- It returns `true` if the user has at least one role and `false` otherwise.
146
+ It returns `true` if the user has at least one of the given roles.
152
147
 
153
148
  **`#roles(context: nil)`**
154
149
 
@@ -166,9 +161,17 @@ To get all roles assigned to the user, grouped by context, use:
166
161
  user.all_roles
167
162
  ```
168
163
 
169
- ---
164
+ **`.assignees(role_name, context: nil)`**
170
165
 
171
- To manipulate roles directly, you can use `Rabarber::Role` methods:
166
+ To get all the users to whom the role is assigned, use:
167
+
168
+ ```rb
169
+ Rabarber::Role.assignees(:admin)
170
+ ```
171
+
172
+ ## Role Management
173
+
174
+ To manipulate roles directly, you can use the following methods:
172
175
 
173
176
  **`.add(role_name, context: nil)`**
174
177
 
@@ -187,9 +190,11 @@ To rename a role, use:
187
190
  ```rb
188
191
  Rabarber::Role.rename(:admin, :administrator)
189
192
  ```
190
- The first argument is the old name, and the second argument is the new name. This will rename the role and return `true`. If the role with a new name already exists, it will return `false`.
191
193
 
192
- The method won't rename the role and will return `false` if it is assigned to any user. To force the rename, use the method with `force: true` argument:
194
+ The old role must exist. If it doesn’t, an error is raised. If a role with the new name already exists, the method returns `false` and the rename fails.
195
+
196
+ The rename also fails if the role is assigned to any user. To force it, use:
197
+
193
198
  ```rb
194
199
  Rabarber::Role.rename(:admin, :administrator, force: true)
195
200
  ```
@@ -202,9 +207,10 @@ To remove a role, use:
202
207
  Rabarber::Role.remove(:admin)
203
208
  ```
204
209
 
205
- This will remove the role and return `true`. If the role doesn't exist, it will return `false`.
210
+ The old role must exist. If it doesnt, an error is raised. The method returns `true` if successful.
211
+
212
+ If the role is assigned to any user, removal will fail. To force it, use:
206
213
 
207
- The method won't remove the role and will return `false` if it is assigned to any user. To force the removal, use the method with `force: true` argument:
208
214
  ```rb
209
215
  Rabarber::Role.remove(:admin, force: true)
210
216
  ```
@@ -219,31 +225,35 @@ Rabarber::Role.names
219
225
 
220
226
  **`.all_names`**
221
227
 
222
- If you need list all roles available in your application, grouped by context, use:
228
+ If you need to list all roles available in your application, grouped by context, use:
223
229
 
224
230
  ```rb
225
231
  Rabarber::Role.all_names
226
232
  ```
227
233
 
228
- **`.assignees(role_name, context: nil)`**
229
-
230
- To get all the users to whom the role is assigned, use:
231
-
232
- ```rb
233
- Rabarber::Role.assignees(:admin)
234
- ```
235
-
236
234
  ## Authorization Rules
237
235
 
238
- Include `Rabarber::Authorization` module into the controller that needs authorization rules to be applied. Typically, it is `ApplicationController`, but it can be any controller of your choice.
236
+ Include `Rabarber::Authorization` module in the controller where you want to define authorization rules. Typically, it is `ApplicationController`, but it can be any controller of your choice. Then use `.with_authorization(options = {})` method, which accepts the same options as Rails’ `before_action`, allowing you to perform authorization checks selectively.
239
237
 
240
238
  ```rb
241
239
  class ApplicationController < ActionController::Base
242
240
  include Rabarber::Authorization
241
+
242
+ with_authorization
243
+
244
+ # ...
245
+ end
246
+
247
+ class InvoicesController < ApplicationController
248
+ with_authorization only: [:update, :destroy]
249
+
243
250
  # ...
244
251
  end
245
252
  ```
246
- This adds `.grant_access(action: nil, roles: nil, context: nil, if: nil, unless: nil)` method which allows you to define the authorization rules.
253
+
254
+ You must ensure the user is authenticated before authorization checks are performed.
255
+
256
+ To define authorization rules, use `.grant_access(action: nil, roles: nil, context: nil, if: nil, unless: nil)` method.
247
257
 
248
258
  The most basic usage of the method is as follows:
249
259
 
@@ -264,6 +274,7 @@ module Crm
264
274
  end
265
275
  end
266
276
  ```
277
+
267
278
  This grants access to `index` action for users with `accountant` or `admin` role, and access to `destroy` action for `admin` users only.
268
279
 
269
280
  You can also define controller-wide rules (without `action` argument):
@@ -293,9 +304,10 @@ module Crm
293
304
  end
294
305
  end
295
306
  ```
296
- This means that `admin` and `manager` have access to all the actions inside `Crm::BaseController` and its children, while `accountant` role has access only to the actions in `Crm::InvoicesController` and its possible children. Users with `marketer` role can only see the dashboard in this example.
297
307
 
298
- Roles can also be omitted:
308
+ In this example, `admin` and `manager` have access to all actions in `Crm::BaseController` and its descendants, while `accountant` role has access only to the actions in `Crm::InvoicesController`. Users with `marketer` role can only see the dashboard.
309
+
310
+ You can also omit roles to allow unrestricted access:
299
311
 
300
312
  ```rb
301
313
  class OrdersController < ApplicationController
@@ -311,11 +323,10 @@ class InvoicesController < ApplicationController
311
323
  end
312
324
  ```
313
325
 
314
- This allows everyone to access `OrdersController` and its children and also `index` action in `InvoicesController`.
326
+ This allows everyone to access `OrdersController` and its descendants as well as `index` action in `InvoicesController`.
315
327
 
316
- If you've set `must_have_roles` setting to `true`, then only the users with at least one role can gain access. This setting can be useful if your requirements are such that users without roles are not allowed to access anything.
328
+ Rules defined in descendant classes don't override ancestor rules but rather add to them:
317
329
 
318
- Also keep in mind that rules defined in child classes don't override parent rules but rather add to them:
319
330
  ```rb
320
331
  module Crm
321
332
  class BaseController < ApplicationController
@@ -331,9 +342,11 @@ module Crm
331
342
  end
332
343
  end
333
344
  ```
345
+
334
346
  This means that `Crm::InvoicesController` is still accessible to `admin` but is also accessible to `accountant`.
335
347
 
336
- This applies as well to multiple rules defined for the same controller or action:
348
+ This also applies when defining multiple rules for the same controller or action:
349
+
337
350
  ```rb
338
351
  module Crm
339
352
  class OrdersController < ApplicationController
@@ -348,11 +361,12 @@ module Crm
348
361
  end
349
362
  end
350
363
  ```
364
+
351
365
  This will add rules for `manager` and `admin` roles for all actions in `Crm::OrdersController`, and for `client` and `accountant` roles for the `show` action.
352
366
 
353
367
  ## Dynamic Authorization Rules
354
368
 
355
- For more complex cases, Rabarber provides dynamic rules:
369
+ For more complex scenarios, Rabarber supports dynamic authorization rules:
356
370
 
357
371
  ```rb
358
372
  module Crm
@@ -394,9 +408,11 @@ module Crm
394
408
  end
395
409
  end
396
410
  ```
397
- You can pass a dynamic rule as `if` or `unless` argument. It can be a symbol, in which case the method with that name will be called, or alternatively it can be a proc that will be executed within the context of the controller instance at request time.
411
+
412
+ You can pass a dynamic rule as `if` or `unless` argument. You can pass a symbol (method name) or a proc. Symbols refer to instance methods, and procs are evaluated in the controller at request time.
398
413
 
399
414
  You can use only dynamic rules without specifying roles if that suits your needs:
415
+
400
416
  ```rb
401
417
  class InvoicesController < ApplicationController
402
418
  grant_access action: :index, if: -> { current_user.company == Company.find(params[:company_id]) }
@@ -405,7 +421,9 @@ class InvoicesController < ApplicationController
405
421
  end
406
422
  end
407
423
  ```
408
- This basically allows you to use Rabarber as a policy-based authorization library by calling your own custom policy within a dynamic rule:
424
+
425
+ This allows you to use Rabarber as a policy-based authorization library by calling your own custom policy within a dynamic rule:
426
+
409
427
  ```rb
410
428
  class InvoicesController < ApplicationController
411
429
  grant_access action: :index, if: -> { InvoicesPolicy.new(current_user).can_access?(:index) }
@@ -417,9 +435,9 @@ end
417
435
 
418
436
  ## Context / Multi-tenancy
419
437
 
420
- Rabarber supports multi-tenancy by providing a context feature. This allows you to define and authorize roles and rules within a specific context.
438
+ Rabarber supports multi-tenancy through its context feature. This allows you to define and authorize roles and rules within a specific context.
421
439
 
422
- Every Rabarber method can accept a context as an additional keyword argument. By default, the context is set to `nil`, meaning the roles are global. Thus, all examples from other sections of this README are valid for global roles. Apart from being global, the context can be an instance of ActiveRecord model or a class.
440
+ Every Rabarber method can accept a context as an additional keyword argument. By default, the context is set to `nil`, meaning the roles are global. Thus, all examples from other sections of this README are valid for global roles. Besides being global, context can also be an instance of an `ActiveRecord` model or a class.
423
441
 
424
442
  E.g., consider a model named `Project`, where each project has its owner and regular members. Roles can be defined like this:
425
443
 
@@ -428,7 +446,7 @@ user.assign_roles(:owner, context: project)
428
446
  another_user.assign_roles(:member, context: project)
429
447
  ```
430
448
 
431
- Then the roles can be verified:
449
+ You can then check roles like this:
432
450
 
433
451
  ```rb
434
452
  user.has_role?(:owner, context: project)
@@ -441,7 +459,7 @@ A role can also be added using a class as a context, e.g., for project admins wh
441
459
  user.assign_roles(:admin, context: Project)
442
460
  ```
443
461
 
444
- And then it can also be verified:
462
+ And to check it:
445
463
 
446
464
  ```rb
447
465
  user.has_role?(:admin, context: Project)
@@ -471,7 +489,7 @@ class ProjectsController < ApplicationController
471
489
  end
472
490
  ```
473
491
 
474
- It's important to note that role names are not unique globally but are unique within the scope of their context. E.g., `user.assign_roles(:admin, context: Project)` and `user.assign_roles(:admin)` assign different roles to the user. The same as `Rabarber::Role.add(:admin, context: Project)` and `Rabarber::Role.add(:admin)` create different roles.
492
+ Role names are scoped by context, i.e. `admin` in a project is different from a global `admin`, or from an `admin` in another project.
475
493
 
476
494
  If you want to see all the roles assigned to a user within a specific context, you can use:
477
495
 
@@ -485,16 +503,29 @@ Or if you want to get all the roles available in a specific context, you can use
485
503
  Rabarber::Role.names(context: Project)
486
504
  ```
487
505
 
506
+ If a context object (e.g., a project) is deleted, any roles tied to it automatically become irrelevant and are no longer returned by role queries. Rabarber treats them as orphaned and ignores them.
507
+
508
+ However, if a context class is renamed (e.g., `Project` becomes `Campaign`), an exception will be raised the next time Rabarber attempts to load roles for that class. This is to ensure you explicitly handle the migration, either by migrating existing roles to the new context or by cleaning up old data.
509
+
510
+ To help with such scenarios, Rabarber provides two helper methods that can be called in migrations:
511
+
512
+ - `migrate_authorization_context!(old_context, new_context)` - renames a context
513
+ - `delete_authorization_context!(context)` – removes roles tied to a deleted context
514
+
515
+ These are irreversible data migrations.
516
+
488
517
  ## When Unauthorized
489
518
 
490
- By default, in the event of an unauthorized attempt, Rabarber redirects the user back if the request format is HTML (with fallback to the root path), and returns a 401 (Unauthorized) status code otherwise.
519
+ By default, Rabarber redirects back on unauthorized access if the request format is HTML (falling back to the root path), and returns a 401 Unauthorized for other formats.
491
520
 
492
- This behavior can be customized by overriding private `when_unauthorized` method:
521
+ You can customize this behavior by overriding the private `when_unauthorized` method:
493
522
 
494
523
  ```rb
495
524
  class ApplicationController < ActionController::Base
496
525
  include Rabarber::Authorization
497
526
 
527
+ with_authorization
528
+
498
529
  # ...
499
530
 
500
531
  private
@@ -518,11 +549,11 @@ class TicketsController < ApplicationController
518
549
  end
519
550
  ```
520
551
 
521
- This method accepts the same options as `skip_before_action` method in Rails.
552
+ This method accepts the same options as Rails’ `skip_before_action`.
522
553
 
523
554
  ## View Helpers
524
555
 
525
- Rabarber also provides a couple of helpers that can be used in views: `visible_to(*roles, context: nil, &block)` and `hidden_from(*roles, context: nil, &block)`. To use them, simply include `Rabarber::Helpers` in the desired helper. Usually it is `ApplicationHelper`, but it can be any helper of your choice.
556
+ Rabarber provides two helpers for use in views: `visible_to(*roles, context: nil, &block)` and `hidden_from(*roles, context: nil, &block)`. To enable them, include `Rabarber::Helpers` in your helper module, typically `ApplicationHelper`.
526
557
 
527
558
  ```rb
528
559
  module ApplicationHelper
@@ -545,16 +576,6 @@ The usage is straightforward:
545
576
  <% end %>
546
577
  ```
547
578
 
548
- ## Audit Trail
549
-
550
- Rabarber supports audit trail, which provides a record of user access control activity. This feature logs the following events:
551
-
552
- - Role assignments to users
553
- - Role revocations from users
554
- - Unauthorized access attempts
555
-
556
- The logs are written to the file `log/rabarber_audit.log` unless the `audit_trail_enabled` configuration option is set to `false`.
557
-
558
579
  ## Problems?
559
580
 
560
581
  Facing a problem or want to suggest an enhancement?
@@ -568,12 +589,19 @@ Encountered a bug?
568
589
 
569
590
  ## Contributing
570
591
 
571
- Before creating an issue or a pull request, please read the [contributing guidelines](https://github.com/enjaku4/rabarber/blob/main/CONTRIBUTING.md).
592
+ Before creating an issue or a pull request, please read the [contributing guidelines](https://github.com/brownboxdev/rabarber/blob/main/CONTRIBUTING.md).
572
593
 
573
594
  ## Code of Conduct
574
595
 
575
- Everyone interacting in the Rabarber project is expected to follow the [code of conduct](https://github.com/enjaku4/rabarber/blob/main/CODE_OF_CONDUCT.md).
596
+ Everyone interacting in the Rabarber project is expected to follow the [code of conduct](https://github.com/brownboxdev/rabarber/blob/main/CODE_OF_CONDUCT.md).
597
+
598
+ ## Old Versions
599
+
600
+ Only the latest major version is supported. Older versions are obsolete and not maintained, but their READMEs are available here for reference:
601
+
602
+ [v4.x.x](https://github.com/brownboxdev/rabarber/blob/9353e70281971154d5acd70693620197a132c543/README.md) | [v3.x.x](https://github.com/brownboxdev/rabarber/blob/3bb273de7e342004abc7ef07fa4d0a9a3ce3e249/README.md)
603
+ | [v2.x.x](https://github.com/brownboxdev/rabarber/blob/875b357ea949404ddc3645ad66eddea7ed4e2ee4/README.md) | [v1.x.x](https://github.com/brownboxdev/rabarber/blob/b81428429404e197d70317b763e7b2a21e02c296/README.md)
576
604
 
577
605
  ## License
578
606
 
579
- The gem is available as open source under the terms of the [MIT License](https://github.com/enjaku4/rabarber/blob/main/LICENSE.txt).
607
+ The gem is available as open source under the terms of the [MIT License](https://github.com/brownboxdev/rabarber/blob/main/LICENSE.txt).
@@ -6,27 +6,30 @@ module Rabarber
6
6
  class Configuration
7
7
  include Singleton
8
8
 
9
- attr_reader :audit_trail_enabled, :cache_enabled, :current_user_method, :must_have_roles
9
+ attr_reader :cache_enabled, :current_user_method
10
+ attr_accessor :user_model_name
10
11
 
11
12
  def initialize
12
- @audit_trail_enabled = true
13
13
  @cache_enabled = true
14
14
  @current_user_method = :current_user
15
- @must_have_roles = false
15
+ @user_model_name = "User"
16
16
  end
17
17
 
18
- [:audit_trail_enabled, :cache_enabled, :must_have_roles].each do |method_name|
19
- define_method(:"#{method_name}=") do |value|
20
- instance_variable_set(:"@#{method_name}", Rabarber::Input::Types::Boolean.new(
21
- value, Rabarber::ConfigurationError, "Configuration '#{method_name}' must be a Boolean"
22
- ).process)
23
- ActiveSupport::Deprecation.new("5.0.0", "rabarber").warn("Rabarber’s ‘must_have_roles’ configuration option is deprecated and will be removed in the next major version!") if method_name == :must_have_roles
24
- end
18
+ def cache_enabled=(value)
19
+ @cache_enabled = Rabarber::Input::Types::Boolean.new(
20
+ value, Rabarber::ConfigurationError, "Configuration `cache_enabled` must be a Boolean"
21
+ ).process
25
22
  end
26
23
 
27
24
  def current_user_method=(method_name)
28
25
  @current_user_method = Rabarber::Input::Types::Symbol.new(
29
- method_name, Rabarber::ConfigurationError, "Configuration 'current_user_method' must be a Symbol or a String"
26
+ method_name, Rabarber::ConfigurationError, "Configuration `current_user_method` must be a Symbol or a String"
27
+ ).process
28
+ end
29
+
30
+ def user_model
31
+ Rabarber::Input::ArModel.new(
32
+ @user_model_name, Rabarber::ConfigurationError, "Configuration `user_model_name` must be an ActiveRecord model name"
30
33
  ).process
31
34
  end
32
35
  end
@@ -5,11 +5,17 @@ module Rabarber
5
5
  extend ActiveSupport::Concern
6
6
  include Rabarber::Core::Roleable
7
7
 
8
- included { before_action :verify_access }
9
-
10
8
  class_methods do
9
+ def with_authorization(options = {})
10
+ before_action :with_authorization, **options
11
+ rescue ArgumentError => e
12
+ raise Rabarber::Error, e.message
13
+ end
14
+
11
15
  def skip_authorization(options = {})
12
- skip_before_action :verify_access, **options
16
+ skip_before_action :with_authorization, **options
17
+ rescue ArgumentError => e
18
+ raise Rabarber::Error, e.message
13
19
  end
14
20
 
15
21
  def grant_access(action: nil, roles: nil, context: nil, if: nil, unless: nil)
@@ -26,15 +32,9 @@ module Rabarber
26
32
 
27
33
  private
28
34
 
29
- def verify_access
30
- Rabarber::Core::PermissionsIntegrityChecker.new(self.class).run! unless Rails.configuration.eager_load
31
-
35
+ def with_authorization
32
36
  return if Rabarber::Core::Permissions.access_granted?(roleable, action_name.to_sym, self)
33
37
 
34
- Rabarber::Audit::Events::UnauthorizedAttempt.trigger(
35
- roleable, path: request.path, request_method: request.request_method
36
- )
37
-
38
38
  when_unauthorized
39
39
  end
40
40
 
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Core
5
+ module IntegrityChecker
6
+ extend self
7
+
8
+ def run!
9
+ check_for_missing_class_context
10
+ prune_missing_instance_context
11
+ end
12
+
13
+ private
14
+
15
+ def check_for_missing_class_context
16
+ Rabarber::Role.where.not(context_type: nil).distinct.pluck(:context_type).each do |context_class|
17
+ context_class.constantize
18
+ rescue NameError => e
19
+ raise Rabarber::Error, "Context not found: class #{e.name} may have been renamed or deleted"
20
+ end
21
+ end
22
+
23
+ def prune_missing_instance_context
24
+ ids = Rabarber::Role.where.not(context_id: nil).includes(:context).filter_map do |role|
25
+ role.context
26
+ nil
27
+ rescue ActiveRecord::RecordNotFound
28
+ role.id
29
+ end
30
+
31
+ return if ids.empty?
32
+
33
+ ActiveRecord::Base.transaction do
34
+ ActiveRecord::Base.connection.execute(
35
+ ActiveRecord::Base.sanitize_sql(
36
+ ["DELETE FROM rabarber_roles_roleables WHERE role_id IN (?)", ids]
37
+ )
38
+ )
39
+ Rabarber::Role.where(id: ids).delete_all
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -32,6 +32,11 @@ module Rabarber
32
32
  def action_rules
33
33
  instance.storage[:action_rules]
34
34
  end
35
+
36
+ def reset!
37
+ instance.storage[:controller_rules].clear
38
+ instance.storage[:action_rules].clear
39
+ end
35
40
  end
36
41
  end
37
42
  end