rabarber 1.4.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bcddaf07627eb382c58a733150e460348527476d2234f65fe0db2760bce6206f
4
- data.tar.gz: 3d1bbfab2a57d860bcb9656cadb5606d09674f887a58b96db0897c3516aed5d2
3
+ metadata.gz: f719eb670170521e94a58a1c75d30110699ab941da6d5dae151fbf53e0eb9880
4
+ data.tar.gz: bd06646e15ab2eb5ff7b49d2a18316c4b539b95aa98bd2ec1b4de5c6b5fb921a
5
5
  SHA512:
6
- metadata.gz: e5ae51e17b580757cc427f269b43155ca3ea5eda5b4813be5d023c273f2271d96108639e24c1921ace823de4cc06b43c03372eb98d64f6d4376f9628e7b6d616
7
- data.tar.gz: 232a9ded49264955b8cf7d22de5a1443947dd84d90f44f15f6dc9c9346ee7b1cee56afa85a55bf44bf5325bb1d26e17e6fcf0b8076d3f14381a9bb43254038ab
6
+ metadata.gz: 0db86c7d46337decbe9972ea3b0c1ad30e1c66f2b76b3ef27a494ef8c2ecc9bcf35ce3f135360e74045b7f20beb38149f5ca308af0cb3d3a0db829ff9dc7147b
7
+ data.tar.gz: d1a20c732318d12ccfe49338df7338dcf09bd1222fd574e8581d035cb38b55295e501bfa45ef63ea0a556a8c21a28abdad7d06ca765c3f14eed6e6cd98db93be
data/CHANGELOG.md CHANGED
@@ -1,27 +1,53 @@
1
- ## 1.4.0
1
+ ## v2.0.0
2
+
3
+ ### Breaking:
4
+
5
+ - Removed `when_actions_missing` and `when_roles_missing` configuration options
6
+ - Replaced `when_unauthorized` configuration option with an overridable controller method
7
+ - Renamed `Rabarber::Role.assignees_for` method to `Rabarber::Role.assignees`
8
+
9
+ To upgrade to v2.0.0, please refer to the [migration guide](https://github.com/enjaku4/rabarber/discussions/52).
10
+
11
+ ### Features:
12
+
13
+ - Added support for UUID primary keys
14
+
15
+ ### Bugs:
16
+
17
+ - Fixed the issue where an error would occur if the user was not authenticated
18
+
19
+ ### Misc:
20
+
21
+ - Significant refactoring and code improvements
22
+
23
+ ## v1.4.1
24
+
25
+ - Fix an issue where an error could be raised when using controller-wide dynamic rules
26
+
27
+ ## v1.4.0
2
28
 
3
29
  - Add 'Audit trail' feature: Logging of role assignments, revocations, and unauthorized access attempts
4
30
  - Add `audit_trail_enabled` configuration option, allowing to enable or disable the audit trail
5
31
  - Deprecate `when_actions_missing` and `when_roles_missing` configuration options (see [the discussion](https://github.com/enjaku4/rabarber/discussions/48))
6
32
 
7
- ## 1.3.1
33
+ ## v1.3.1
8
34
 
9
35
  - Add `Rabarber::Role.assignees_for` method
10
36
  - Fix inconsistent behavior where passing `nil` as a role name to role management methods would raise an `ActiveRecord` error instead of `Rabarber` error
11
37
  - Various minor code improvements
12
38
 
13
- ## 1.3.0
39
+ ## v1.3.0
14
40
 
15
41
  - Add methods to directly add, rename, and remove roles
16
42
  - Modify `Rabarber::HasRoles#assign_roles` and `Rabarber::HasRoles#revoke_roles` methods to return the list of roles assigned to the user
17
43
  - Minor performance improvements
18
44
 
19
- ## 1.2.2
45
+ ## v1.2.2
20
46
 
21
47
  - Refactor to improve readability and maintainability
22
48
  - Fix minor code errors
23
49
 
24
- ## 1.2.1
50
+ ## v1.2.1
25
51
 
26
52
  - Cache roles to avoid unnecessary database queries
27
53
  - Introduce `cache_enabled` configuration option allowing to enable or disable role caching
@@ -29,61 +55,61 @@
29
55
  - Fix an issue where an error would be raised if the user is not authenticated
30
56
  - Various minor improvements
31
57
 
32
- ## 1.2.0
58
+ ## v1.2.0
33
59
 
34
60
  - Enhance handling of missing actions and roles specified in `grant_access` method by raising an error for missing actions and logging a warning for missing roles
35
61
  - Introduce `when_actions_missing` and `when_roles_missing` configuration options, allowing to customize the behavior when actions or roles are not found
36
62
 
37
- ## 1.1.0
63
+ ## v1.1.0
38
64
 
39
65
  - Add support for `unless` argument in `grant_access` method, allowing to define negated dynamic rules
40
66
  - Fix a bug where specifying a dynamic rule as a symbol without specifying an action would result in an error
41
67
 
42
- ## 1.0.5
68
+ ## v1.0.5
43
69
 
44
70
  - Add co-author: [trafium](https://github.com/trafium)
45
71
 
46
- ## 1.0.4
72
+ ## v1.0.4
47
73
 
48
74
  - Allow to use strings as role names
49
75
 
50
- ## 1.0.3
76
+ ## v1.0.3
51
77
 
52
78
  - Enhance clarity by improving error types and messages
53
79
  - Resolve inconsistency in types of role names
54
80
 
55
- ## 1.0.2
81
+ ## v1.0.2
56
82
 
57
83
  - Various enhancements for gem development and release
58
84
  - Modify `Rabarber::HasRoles#roles` method to return an array of role names instead of `Rabarber::Role` objects
59
85
 
60
- ## 1.0.1
86
+ ## v1.0.1
61
87
 
62
88
  - Various enhancements for gem development
63
89
 
64
- ## 1.0.0
90
+ ## v1.0.0
65
91
 
66
92
  - Drop support for Ruby 2.7
67
93
  - Add support for Ruby 3.3
68
94
  - Various minor improvements
69
95
 
70
- ## 0.1.5
96
+ ## v0.1.5
71
97
 
72
98
  - Add missing `foreign_key` option to `CreateRabarberRoles` migration
73
99
  - Allow only lowercase alphanumeric characters and underscores in role names
74
100
 
75
- ## 0.1.4
101
+ ## v0.1.4
76
102
 
77
103
  - Remove `Rabarber::HasRoles#role?` method as unnecessary
78
104
 
79
- ## 0.1.3
105
+ ## v0.1.3
80
106
 
81
107
  - Fully revise and update README for clarity
82
108
 
83
- ## 0.1.2
109
+ ## v0.1.2
84
110
 
85
111
  - Fix check that `Rabarber::HasRoles` can only be included once
86
112
 
87
- ## 0.1.1
113
+ ## v0.1.1
88
114
 
89
115
  - Initial release
data/README.md CHANGED
@@ -9,7 +9,7 @@ Rabarber is a role-based authorization library for Ruby on Rails, primarily desi
9
9
 
10
10
  **Example of Usage**:
11
11
 
12
- Consider a CRM 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. Such authorization rules can be easily defined with Rabarber.
13
13
 
14
14
  ---
15
15
 
@@ -21,39 +21,65 @@ class TicketsController < ApplicationController
21
21
 
22
22
  grant_access action: :index, roles: :manager
23
23
  def index
24
- ...
24
+ # ...
25
25
  end
26
26
 
27
27
  def delete
28
- ...
28
+ # ...
29
29
  end
30
30
  end
31
31
  ```
32
32
  This means that `admin` users can access everything in `TicketsController`, while `manager` role can access only `index` action.
33
33
 
34
+ ## Table of Contents
35
+
36
+ **Gem usage:**
37
+ - [Installation](#installation)
38
+ - [Configuration](#configuration)
39
+ - [Roles](#roles)
40
+ - [Authorization Rules](#authorization-rules)
41
+ - [Dynamic Authorization Rules](#dynamic-authorization-rules)
42
+ - [When Unauthorized](#when-unauthorized)
43
+ - [View Helpers](#view-helpers)
44
+ - [Audit Trail](#audit-trail)
45
+
46
+ **Community Resources:**
47
+ - [Problems?](#problems)
48
+ - [Contributing](#contributing)
49
+ - [Code of Conduct](#code-of-conduct)
50
+
51
+ **Legal:**
52
+ - [License](#license)
53
+
34
54
  ## Installation
35
55
 
36
56
  Add the Rabarber gem to your Gemfile:
37
57
 
38
- ```
58
+ ```rb
39
59
  gem "rabarber"
40
60
  ```
41
61
 
42
62
  Install the gem:
43
63
 
44
- ```
64
+ ```shell
45
65
  bundle install
46
66
  ```
47
67
 
48
68
  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:
49
69
 
50
- ```
70
+ ```shell
51
71
  rails g rabarber:roles users
52
72
  ```
53
73
 
54
- Finally, run the migration to apply the changes to the database:
74
+ Rabarber supports UUIDs as primary keys. If your application uses UUIDs, add `--uuid` option to the generator:
55
75
 
76
+ ```shell
77
+ rails g rabarber:roles users --uuid
56
78
  ```
79
+
80
+ Finally, run the migration to apply the changes to the database:
81
+
82
+ ```shell
57
83
  rails db:migrate
58
84
  ```
59
85
 
@@ -67,29 +93,13 @@ Rabarber.configure do |config|
67
93
  config.cache_enabled = true
68
94
  config.current_user_method = :current_user
69
95
  config.must_have_roles = false
70
- config.when_unauthorized = -> (controller) {
71
- if controller.request.format.html?
72
- controller.redirect_back fallback_location: controller.root_path
73
- else
74
- controller.head :unauthorized
75
- end
76
- }
77
96
  end
78
97
  ```
79
98
 
80
- - `audit_trail_enabled` must be a boolean determining whether the audit trail functionality is enabled. _The audit trail is enabled by default._
81
- - `cache_enabled` must be a boolean determining whether roles are cached. _Roles are cached by default to avoid unnecessary database queries._ If you want to disable caching, set this option to `false`. If caching is enabled and you need to clear the cache, use `Rabarber::Cache.clear` method.
82
- - `current_user_method` must be a symbol representing the method that returns the currently authenticated user. _The default value is `:current_user`._
83
- - `must_have_roles` must be a boolean determining whether a user with no roles can access endpoints permitted to everyone. _The default value is `false` (allowing users without roles to access endpoints permitted to everyone)._
84
- - `when_unauthorized` must be a proc where you can define the behaviour when access is not authorized. Lambda argument `controller` is an instance of the controller where the code is executed. _By default, the user is redirected back if the request format is HTML; otherwise, a 401 Unauthorized response is sent._
85
-
86
- ### Deprecated Configuration Options
87
-
88
- The following configuration options are deprecated and will be removed in the next major version (see [the discussion](https://github.com/enjaku4/rabarber/discussions/48)):
89
-
90
- - `when_actions_missing` must be a proc where you can define the behaviour when the action specified in `grant_access` method cannot be found in the controller. Lambda argument `missing_actions` is an array of symbols, e.g., `[:index]`, while `context` argument is a hash that looks like this: `{ controller: "InvoicesController" }`. This check is performed when the application is initialized if `eager_load` configuration is enabled in Rails and also on every request. _By default, an error is raised when action is missing._
91
-
92
- - `when_roles_missing` must be a proc where you can define the behaviour when the roles specified in `grant_access` method cannot be found in the database. Lambda argument `missing_roles` is an array of symbols, e.g., `[:admin]`, while `context` argument is a hash that looks like this: `{ controller: "InvoicesController", action: "index" }`. This check is performed when the application is initialized if `eager_load` configuration is enabled in Rails and also on every request. _By default, a warning is logged when roles are missing._
99
+ - `audit_trail_enabled` determines whether the audit trail functionality is enabled. The audit trail is enabled by default.
100
+ - `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.
101
+ - `current_user_method` represents the method that returns the currently authenticated user. The default value is `:current_user`.
102
+ - `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).
93
103
 
94
104
  ## Roles
95
105
 
@@ -98,7 +108,7 @@ Include `Rabarber::HasRoles` module in your model representing users in your app
98
108
  ```rb
99
109
  class User < ApplicationRecord
100
110
  include Rabarber::HasRoles
101
- ...
111
+ # ...
102
112
  end
103
113
  ```
104
114
 
@@ -124,7 +134,7 @@ To revoke roles, use:
124
134
  ```rb
125
135
  user.revoke_roles(:accountant, :marketer)
126
136
  ```
127
- If any of the specified roles doesn't exist or the user doesn't have the role you want to revoke, it will be ignored.
137
+ If the user doesn't have the role you want to revoke, it will be ignored.
128
138
 
129
139
  The method returns an array of roles assigned to the user.
130
140
 
@@ -140,7 +150,7 @@ It returns `true` if the user has at least one role and `false` otherwise.
140
150
 
141
151
  **`#roles`**
142
152
 
143
- To view all the roles assigned to the user, use:
153
+ To get all the roles assigned to the user, use:
144
154
 
145
155
  ```rb
146
156
  user.roles
@@ -150,7 +160,7 @@ user.roles
150
160
 
151
161
  To manipulate roles directly, you can use `Rabarber::Role` methods:
152
162
 
153
- **`.add(role)`**
163
+ **`.add(role_name)`**
154
164
 
155
165
  To add a new role, use:
156
166
 
@@ -167,14 +177,14 @@ To rename a role, use:
167
177
  ```rb
168
178
  Rabarber::Role.rename(:admin, :administrator)
169
179
  ```
170
- The first argument is the old name, and the second argument is the new name. This will rename the role and return `true`. If a role with the new name already exists, it will return `false`.
180
+ 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`.
171
181
 
172
182
  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:
173
183
  ```rb
174
184
  Rabarber::Role.rename(:admin, :administrator, force: true)
175
185
  ```
176
186
 
177
- **`.remove(role, force: false)`**
187
+ **`.remove(role_name, force: false)`**
178
188
 
179
189
  To remove a role, use:
180
190
 
@@ -197,12 +207,12 @@ If you need to list all the role names available in your application, use:
197
207
  Rabarber::Role.names
198
208
  ```
199
209
 
200
- **`.assignees_for(role)`**
210
+ **`.assignees(role_name)`**
201
211
 
202
212
  To get all the users to whom the role is assigned, use:
203
213
 
204
214
  ```rb
205
- Rabarber::Role.assignees_for(:admin)
215
+ Rabarber::Role.assignees(:admin)
206
216
  ```
207
217
 
208
218
  ## Authorization Rules
@@ -212,7 +222,7 @@ Include `Rabarber::Authorization` module into the controller that needs authoriz
212
222
  ```rb
213
223
  class ApplicationController < ActionController::Base
214
224
  include Rabarber::Authorization
215
- ...
225
+ # ...
216
226
  end
217
227
  ```
218
228
  This adds `.grant_access(action: nil, roles: nil, if: nil, unless: nil)` method which allows you to define the authorization rules.
@@ -220,19 +230,23 @@ This adds `.grant_access(action: nil, roles: nil, if: nil, unless: nil)` method
220
230
  The most basic usage of the method is as follows:
221
231
 
222
232
  ```rb
223
- class InvoicesController < ApplicationController
233
+ class Crm::InvoicesController < ApplicationController
224
234
  grant_access action: :index, roles: [:accountant, :admin]
225
235
  def index
226
- ...
236
+ @invoices = Invoice.all
237
+ @invoices = @invoices.paid if current_user.has_role?(:accountant)
238
+ # ...
227
239
  end
228
240
 
229
- grant_access action: :delete, roles: :admin
230
- def delete
231
- ...
241
+ grant_access action: :destroy, roles: :admin
242
+ def destroy
243
+ # ...
232
244
  end
233
245
  end
234
246
  ```
235
- This grants access to `index` action for users with `accountant` or `admin` role, and access to `delete` action for `admin` users only.
247
+ This grants access to `index` action for users with `accountant` or `admin` role, and access to `destroy` action for `admin` users only.
248
+
249
+ Please note that Rabarber does not provide any built-in data scoping mechanism as it is not a part of the authorization layer and is not necessarily role specific or has anything to do with the current user. The business logic can vary drastically depending on the application, so you're encouraged to limit the data visibility yourself, for example, in the same way as in the example above, where `accountant` role can only see paid invoices.
236
250
 
237
251
  You can also define controller-wide rules (without `action` argument):
238
252
 
@@ -242,18 +256,18 @@ class Crm::BaseController < ApplicationController
242
256
 
243
257
  grant_access action: :dashboard, roles: :marketer
244
258
  def dashboard
245
- ...
259
+ # ...
246
260
  end
247
261
  end
248
262
 
249
263
  class Crm::InvoicesController < Crm::BaseController
250
264
  grant_access roles: :accountant
251
265
  def index
252
- ...
266
+ # ...
253
267
  end
254
268
 
255
269
  def delete
256
- ...
270
+ # ...
257
271
  end
258
272
  end
259
273
  ```
@@ -264,35 +278,53 @@ Roles can also be omitted:
264
278
  ```rb
265
279
  class OrdersController < ApplicationController
266
280
  grant_access
267
- ...
281
+ # ...
268
282
  end
269
283
 
270
284
  class InvoicesController < ApplicationController
271
285
  grant_access action: :index
272
286
  def index
273
- ...
287
+ # ...
274
288
  end
275
289
  end
276
290
  ```
277
291
 
278
292
  This allows everyone to access `OrdersController` and its children and also `index` action in `InvoicesController`. This extends to scenarios where there is no user present, i.e. when the method responsible for returning the currently authenticated user in your application returns `nil`.
279
293
 
280
- _Be aware that if the user is not authenticated (the method responsible for returning the currently authenticated user in your application returns `nil`), Rabarber will treat this situation as if the user with no roles assigned was authenticated._
294
+ If the user is not authenticated (the method responsible for returning the currently authenticated user in your application returns `nil`), Rabarber will handle this situation as if the user has no roles.
281
295
 
282
- If you've set `must_have_roles` setting to `true`, then, only the users with at least one role can have access. This setting can be useful if your requirements are such that users without roles are not allowed to access anything.
296
+ 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 (or unauthenticated users) are not allowed to access anything.
297
+
298
+ Also keep in mind that rules defined in child classes don't override parent rules but rather add to them:
299
+ ```rb
300
+ class Crm::BaseController < ApplicationController
301
+ grant_access roles: :admin
302
+ # ...
303
+ end
304
+
305
+ class Crm::InvoicesController < Crm::BaseController
306
+ grant_access roles: :accountant
307
+ # ...
308
+ end
309
+ ```
310
+ This means that `Crm::InvoicesController` is still accessible to `admin` but is also accessible to `accountant`.
311
+
312
+ ## Dynamic Authorization Rules
283
313
 
284
314
  For more complex cases, Rabarber provides dynamic rules:
285
315
 
286
316
  ```rb
287
- class OrdersController < ApplicationController
288
- grant_access if: :current_company_accountant?
289
- grant_access unless: :fired?
290
- ...
317
+ class Crm::OrdersController < ApplicationController
318
+ grant_access roles: :manager, if: :company_manager?, unless: :fired?
319
+
320
+ def index
321
+ # ...
322
+ end
291
323
 
292
324
  private
293
325
 
294
- def current_company_accountant?
295
- current_company.accountant == current_user
326
+ def company_manager?
327
+ Company.find(params[:company_id]).manager == current_user
296
328
  end
297
329
 
298
330
  def fired?
@@ -300,33 +332,65 @@ class OrdersController < ApplicationController
300
332
  end
301
333
  end
302
334
 
303
- class InvoicesController < ApplicationController
304
- grant_access action: :index, roles: :accountant, if: -> { current_user.passed_probation_period? }
335
+ class Crm::InvoicesController < ApplicationController
336
+ grant_access roles: :senior_accountant
337
+
338
+ grant_access action: :index, roles: [:secretary, :accountant], if: -> { InvoicesPolicy.new(current_user).can_access?(:index) }
305
339
  def index
306
- ...
340
+ @invoices = Invoice.all
341
+ @invoices = @invoices.where("total < 10000") if current_user.has_role?(:accountant)
342
+ @invoices = @invoices.unpaid if current_user.has_role?(:secretary)
343
+ # ...
307
344
  end
308
345
 
309
- grant_access action: :show, roles: :client, unless: -> { current_user.banned? }
346
+ grant_access action: :show, roles: :accountant, unless: -> { Invoice.find(params[:id]).total > 10_000 }
310
347
  def show
311
- ...
348
+ # ...
312
349
  end
313
350
  end
314
351
  ```
315
- You can pass a dynamic rule as `if` or `unless` argument. It can be a symbol, in which case the method with the same name will be called. Alternatively, it can be a proc, which will be executed within the context of the controller's instance.
352
+ 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. Alternatively, it can be a proc, which will be executed within the context of the controller's instance.
316
353
 
317
- Rules defined in child classes don't override parent rules but rather add to them:
354
+ You can use only dynamic rules without specifying roles if that suits your needs:
318
355
  ```rb
319
- class Crm::BaseController < ApplicationController
320
- grant_access roles: :admin
321
- ...
356
+ class InvoicesController < ApplicationController
357
+ grant_access action: :index, if: -> { current_user.company == Company.find(params[:company_id]) }
358
+ def index
359
+ # ...
360
+ end
361
+ end
362
+ ```
363
+ This basically allows you to use Rabarber as a policy-based authorization library by calling your own custom policy within a dynamic rule:
364
+ ```rb
365
+ class InvoicesController < ApplicationController
366
+ grant_access action: :index, if: -> { InvoicesPolicy.new(current_user).can_access?(:index) }
367
+ def index
368
+ # ...
369
+ end
322
370
  end
371
+ ```
323
372
 
324
- class Crm::InvoicesController < Crm::BaseController
325
- grant_access roles: :accountant
326
- ...
373
+ ## When Unauthorized
374
+
375
+ 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.
376
+
377
+ This behavior can be customized by overriding private `when_unauthorized` method:
378
+
379
+ ```rb
380
+ class ApplicationController < ActionController::Base
381
+ include Rabarber::Authorization
382
+
383
+ # ...
384
+
385
+ private
386
+
387
+ def when_unauthorized
388
+ head :not_found # pretend the page doesn't exist
389
+ end
327
390
  end
328
391
  ```
329
- This means that `Crm::InvoicesController` is still accessible to `admin` but is also accessible to `accountant`.
392
+
393
+ The method can be overridden in different controllers, providing flexibility in handling unauthorized access attempts.
330
394
 
331
395
  ## View Helpers
332
396
 
@@ -335,7 +399,7 @@ Rabarber also provides a couple of helpers that can be used in views: `visible_t
335
399
  ```rb
336
400
  module ApplicationHelper
337
401
  include Rabarber::Helpers
338
- ...
402
+ # ...
339
403
  end
340
404
  ```
341
405
 
@@ -367,7 +431,7 @@ The logs are written to the file `log/rabarber_audit.log` unless the `audit_trai
367
431
 
368
432
  Facing a problem or want to suggest an enhancement?
369
433
 
370
- - **Open a Discussion**: If you have a question, experience difficulties using the gem, or have an improvement suggestion, feel free to use the Discussions section.
434
+ - **Open a Discussion**: If you have a question, experience difficulties using the gem, or have a suggestion for improvements, feel free to use the Discussions section.
371
435
 
372
436
  Encountered a bug?
373
437
 
@@ -376,12 +440,12 @@ Encountered a bug?
376
440
 
377
441
  ## Contributing
378
442
 
379
- Before opening an issue or creating a pull request, please read the [contributing guidelines](https://github.com/enjaku4/rabarber/blob/main/CONTRIBUTING.md).
380
-
381
- ## License
382
-
383
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
443
+ Before creating an issue or a pull request, please read the [contributing guidelines](https://github.com/enjaku4/rabarber/blob/main/CONTRIBUTING.md).
384
444
 
385
445
  ## Code of Conduct
386
446
 
387
447
  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).
448
+
449
+ ## License
450
+
451
+ The gem is available as open source under the terms of the [MIT License](https://github.com/enjaku4/rabarber/blob/main/LICENSE.txt).
@@ -10,6 +10,8 @@ module Rabarber
10
10
 
11
11
  argument :table_name, type: :string, required: true
12
12
 
13
+ class_option :uuid, type: :boolean, default: false, desc: "Use UUIDs as primary keys"
14
+
13
15
  def create_migrations
14
16
  migration_template "create_rabarber_roles.rb.erb", "db/migrate/create_rabarber_roles.rb"
15
17
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  class CreateRabarberRoles < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version.to_s %>]
4
4
  def change
5
- create_table :rabarber_roles do |t|
5
+ create_table :rabarber_roles<%= ", id: :uuid" if options[:uuid] %> do |t|
6
6
  t.string :name, null: false, index: { unique: true }
7
7
  t.timestamps
8
8
  end
9
9
 
10
10
  create_table :rabarber_roles_roleables, id: false do |t|
11
- t.belongs_to :role, null: false, index: true, foreign_key: { to_table: :rabarber_roles }
12
- t.belongs_to :roleable, null: false, index: true, foreign_key: { to_table: <%= table_name.to_sym.inspect %> }
11
+ t.belongs_to :role, null: false, index: true, foreign_key: { to_table: :rabarber_roles }<%= ", type: :uuid" if options[:uuid] %>
12
+ t.belongs_to :roleable, null: false, index: true, foreign_key: { to_table: <%= table_name.to_sym.inspect %> }<%= ", type: :uuid" if options[:uuid] %>
13
13
  end
14
14
 
15
15
  add_index :rabarber_roles_roleables, [:role_id, :roleable_id], unique: true
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../logger"
4
+
5
+ module Rabarber
6
+ module Audit
7
+ module Events
8
+ class Base
9
+ attr_reader :roleable, :specifics
10
+
11
+ def self.trigger(roleable, specifics)
12
+ new(roleable, specifics).send(:log)
13
+ end
14
+
15
+ private
16
+
17
+ def initialize(roleable, specifics)
18
+ raise ArgumentError, "Roleable is required for #{self.class} event" if roleable.nil? && !nil_roleable_allowed?
19
+
20
+ @roleable = roleable
21
+ @specifics = specifics
22
+ end
23
+
24
+ def nil_roleable_allowed?
25
+ raise NotImplementedError
26
+ end
27
+
28
+ def log
29
+ Rabarber::Audit::Logger.log(log_level, message)
30
+ end
31
+
32
+ def log_level
33
+ raise NotImplementedError
34
+ end
35
+
36
+ def message
37
+ raise NotImplementedError
38
+ end
39
+
40
+ def identity
41
+ roleable_identity(with_roles: identity_with_roles?)
42
+ end
43
+
44
+ def identity_with_roles?
45
+ raise NotImplementedError
46
+ end
47
+
48
+ def roleable_identity(with_roles:)
49
+ if roleable
50
+ model_name = roleable.model_name.human
51
+ primary_key = roleable.class.primary_key
52
+ roleable_id = roleable.public_send(primary_key)
53
+
54
+ roles = with_roles ? ", roles: #{roleable.roles}" : ""
55
+
56
+ "#{model_name} with #{primary_key}: '#{roleable_id}'#{roles}"
57
+ else
58
+ "Unauthenticated #{Rabarber::HasRoles.roleable_class.model_name.human.downcase}"
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end