rabarber 5.2.3 → 5.2.5

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: 58580c8850cc6cde86318dee64ffcf28bf9daea4ced15eddaf8ff6e0148670bc
4
- data.tar.gz: 6bd2d216d86d2c30d650cb190f7da17948b693bb9e0f7acd8df0cab2dfdae8ae
3
+ metadata.gz: 23cc4a1c2e65a3b450653b65df49633601756ada11844173b0c6314c41067ca9
4
+ data.tar.gz: 95153a3172c58bf636cb4d17981ba70336a292368f6bac26c2b6a107c4fcbaaa
5
5
  SHA512:
6
- metadata.gz: '085794b488e723adbc08a8b0ec13005cd4352612b452df86ee85364ef3cdbe76288cc0f77d088844b6843134119048d26eb256c8999a0c86cdc0a9505aa5a4eb'
7
- data.tar.gz: 5c105b394e8984e8f3951c59e2a21b1c96508047a624fd86299ad6471d05d3e4bd6715363ecdf18d845fc6d788f569c7e4d5c6c41cec7cfb75eabaaf754f5d99
6
+ metadata.gz: 180407341e8e4e700fff624ab12de40d9aa66ed4e132e8ddc92c0c9cb4c010309194e7b37bc825a9a92a0e9baf64022a165788055ccba6b41e60aab8d040fc20
7
+ data.tar.gz: 882d08be5cab1db66d0056ef5e0ace724d2d8ce633cdf75af808d28980faeadbdf9e56c4362e3b7197a89b0de80925f77b2dafb12c5f6e44b1f21cb43be0730d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## v5.2.5
2
+
3
+ ### Misc:
4
+
5
+ - Added support for Ruby 4
6
+
7
+ ## v5.2.4
8
+
9
+ ### Misc:
10
+
11
+ - Added support for Rails 8.1
12
+
1
13
  ## v5.2.3
2
14
 
3
15
  ### Bugs:
@@ -85,7 +97,7 @@ To upgrade to v5.0.0, please refer to the [migration guide](https://github.com/e
85
97
 
86
98
  - Optimized various parts of the code and database queries for improved performance
87
99
  - Streamlined the authorization process by requiring the user to be authenticated before access is verified
88
- - Rabarber now skips roles with missing instance context and prunes them automatically; missing class context still raises errors
100
+ - Rabarber now skips roles with missing instance context; missing class context still raises errors
89
101
 
90
102
  ## v4.1.4
91
103
 
data/README.md CHANGED
@@ -5,15 +5,13 @@
5
5
  [![Github Actions badge](https://github.com/enjaku4/rabarber/actions/workflows/ci.yml/badge.svg)](https://github.com/enjaku4/rabarber/actions/workflows/ci.yml)
6
6
  [![License](https://img.shields.io/github/license/enjaku4/rabarber.svg)](LICENSE)
7
7
 
8
- Rabarber is a role-based authorization library for Ruby on Rails that focuses on controller-level access control. Rather than answering domain questions like "can this user create a post?", Rabarber answers "can this user access the create post endpoint?", providing a clean separation between authorization and business logic.
8
+ Rabarber is a role-based authorization library for Ruby on Rails. It provides a set of tools for managing user roles and defining access rules, with support for multi-tenancy through context.
9
9
 
10
- **Key Features:**
10
+ **Example of Usage:**
11
11
 
12
- - Role-based authorization
13
- - Controller-level access control
14
- - Multi-tenancy support through contextual roles
15
- - Dynamic authorization with conditional logic
16
- - View helpers for role-based content rendering
12
+ Consider a CRM system where users with different roles have distinct access levels. For instance, the role `accountant` can access invoice data but not marketing information, while the role `analyst` can view marketing data but not detailed financial records. You can define such authorization rules easily with Rabarber.
13
+
14
+ ___
17
15
 
18
16
  And this is how your controller might look with Rabarber:
19
17
 
@@ -23,25 +21,28 @@ class TicketsController < ApplicationController
23
21
 
24
22
  grant_access action: :index, roles: :manager
25
23
  def index
26
- # Accessible to admin and manager roles
24
+ # ...
27
25
  end
28
26
 
29
27
  def destroy
30
- # Accessible to admin role only
28
+ # ...
31
29
  end
32
30
  end
33
31
  ```
34
32
 
33
+ This means that `admin` users can access everything in `TicketsController`, while the `manager` role can access only the `index` action.
34
+
35
35
  ## Table of Contents
36
36
 
37
37
  **Gem Usage:**
38
38
  - [Installation](#installation)
39
39
  - [Configuration](#configuration)
40
40
  - [User Role Methods](#user-role-methods)
41
- - [Role Management](#role-management)
42
- - [Controller Authorization](#controller-authorization)
43
- - [Dynamic Rules](#dynamic-rules)
44
- - [Multi-tenancy / Context](#multi-tenancy--context)
41
+ - [Direct Role Management](#direct-role-management)
42
+ - [Authorization](#authorization)
43
+ - [Dynamic Authorization Rules](#dynamic-authorization-rules)
44
+ - [When Unauthorized](#when-unauthorized)
45
+ - [Context / Multi-tenancy](#context--multi-tenancy)
45
46
  - [View Helpers](#view-helpers)
46
47
 
47
48
  **Community Resources:**
@@ -64,7 +65,7 @@ Install the gem:
64
65
  bundle install
65
66
  ```
66
67
 
67
- Generate the migration for role storage (replace `users` with your user table name if different):
68
+ Generate the migration to store roles (replace `users` with your table name if different):
68
69
 
69
70
  ```shell
70
71
  # For standard integer IDs
@@ -82,7 +83,7 @@ rails db:migrate
82
83
 
83
84
  ## Configuration
84
85
 
85
- Configure Rabarber in an initializer if customization is needed:
86
+ Create an initializer to customize Rabarber's behavior (optional):
86
87
 
87
88
  ```rb
88
89
  Rabarber.configure do |config|
@@ -92,7 +93,7 @@ Rabarber.configure do |config|
92
93
  end
93
94
  ```
94
95
 
95
- Roles are cached by default for performance. To clear the role cache manually:
96
+ Roles are cached by default for better performance. Clear the cache manually when needed:
96
97
 
97
98
  ```rb
98
99
  Rabarber::Cache.clear
@@ -106,13 +107,13 @@ Your user model is automatically augmented with role management methods:
106
107
 
107
108
  ```rb
108
109
  # Assign roles (creates roles if they don't exist)
109
- user.assign_roles(:accountant, :manager)
110
+ user.assign_roles(:admin, :manager)
110
111
 
111
- # Assign only existing roles
112
+ # Assign only existing roles (don't create new ones)
112
113
  user.assign_roles(:accountant, :manager, create_new: false)
113
114
 
114
115
  # Revoke specific roles
115
- user.revoke_roles(:accountant, :manager)
116
+ user.revoke_roles(:admin, :manager)
116
117
 
117
118
  # Revoke all roles
118
119
  user.revoke_all_roles
@@ -136,9 +137,9 @@ user.all_roles
136
137
  User.with_role(:admin, :manager)
137
138
  ```
138
139
 
139
- ## Role Management
140
+ ## Direct Role Management
140
141
 
141
- ### Direct Role Operations
142
+ You can also manage roles directly:
142
143
 
143
144
  ```rb
144
145
  # Create a new role
@@ -159,41 +160,39 @@ Rabarber.roles
159
160
  Rabarber.all_roles
160
161
  ```
161
162
 
162
- > **Note:** Some methods have been deprecated in favor of the new API shown above. The deprecated methods still work but will be removed in a future major version. See the [changelog](https://github.com/enjaku4/rabarber/blob/main/CHANGELOG.md#v520) for the complete list of deprecated methods and their new counterparts.
163
+ > **Note:** Some methods have been deprecated in favor of the new API shown above. Deprecated methods still work but will be removed in a future major version. See the [changelog](https://github.com/enjaku4/rabarber/blob/main/CHANGELOG.md#v520) for the complete list of deprecated methods and their replacements.
163
164
 
164
- ## Controller Authorization
165
+ ## Authorization
165
166
 
166
- ### Basic Setup
167
+ ### Setup
167
168
 
168
- Include the authorization module and configure protection:
169
+ Include `Rabarber::Authorization` module in your controllers and configure protection:
169
170
 
170
171
  ```rb
171
172
  class ApplicationController < ActionController::Base
172
173
  include Rabarber::Authorization
173
174
 
174
- with_authorization # Enable authorization for all actions
175
- end
176
-
177
- class InvoicesController < ApplicationController
178
- with_authorization only: [:update, :destroy] # Selective authorization
175
+ with_authorization # Enable authorization check for all actions in all controllers by default
179
176
  end
180
177
  ```
181
178
 
182
- Authorization requires an authenticated user to be present.
183
-
184
- ### Skip Authorization
185
-
186
- You can also selectively skip authorization:
179
+ You can also enable authorization checks selectively. Both `with_authorization` and `skip_authorization` work exactly the same as Rails' `before_action` and `skip_before_action` methods:
187
180
 
188
181
  ```rb
189
182
  class TicketsController < ApplicationController
190
- skip_authorization except: [:create, :update, :destroy]
183
+ skip_authorization only: [:index, :show] # Skip authorization for specific actions
184
+ end
185
+
186
+ class InvoicesController < ApplicationController
187
+ with_authorization except: [:index] # Enable authorization for all actions except index
191
188
  end
192
189
  ```
193
190
 
191
+ Authorization requires an authenticated user. Rabarber will raise an error if no user is found via the configured `current_user_method`. Ensure authentication happens before authorization.
192
+
194
193
  ### Authorization Rules
195
194
 
196
- Define access rules using `grant_access`:
195
+ Define authorization rules using `grant_access`:
197
196
 
198
197
  ```rb
199
198
  class TicketsController < ApplicationController
@@ -212,9 +211,7 @@ class TicketsController < ApplicationController
212
211
  end
213
212
  ```
214
213
 
215
- ### Additive Rules
216
-
217
- Rules are additive across inheritance chains and for the same actions:
214
+ Authorization rules are additive - they combine across inheritance chains and when defined multiple times for the same action:
218
215
 
219
216
  ```rb
220
217
  class BaseController < ApplicationController
@@ -232,9 +229,7 @@ class InvoicesController < BaseController
232
229
  end
233
230
  ```
234
231
 
235
- ### Unrestricted Access
236
-
237
- Omit roles to allow unrestricted access:
232
+ It's possible to omit roles to allow unrestricted access:
238
233
 
239
234
  ```rb
240
235
  class UnrestrictedController < ApplicationController
@@ -254,64 +249,78 @@ class MixedController < ApplicationController
254
249
  end
255
250
  ```
256
251
 
257
- ### Custom Unauthorized Handling
252
+ ## Dynamic Authorization Rules
258
253
 
259
- Override `when_unauthorized` method to customize unauthorized access behavior:
254
+ For more complex scenarios, Rabarber supports dynamic authorization rules:
260
255
 
261
256
  ```rb
262
- class ApplicationController < ActionController::Base
263
- include Rabarber::Authorization
257
+ class OrdersController < ApplicationController
258
+ grant_access roles: :manager, unless: -> { current_user.suspended? }
264
259
 
265
- with_authorization
260
+ grant_access action: :show, roles: :client, if: :user_company_matches_order?
261
+ def show
262
+ # ...
263
+ end
266
264
 
267
265
  private
268
266
 
269
- def when_unauthorized
270
- head :not_found # Custom behavior to hide existence of protected resources
267
+ def user_company_matches_order?
268
+ current_user.company == Order.find(params[:id]).company
271
269
  end
272
270
  end
273
271
  ```
274
272
 
275
- By default, when unauthorized, Rabarber will redirect back (HTML format) or return 403 (other formats).
276
-
277
- ## Dynamic Rules
273
+ You can pass a dynamic rule as an `if` or `unless` argument, which can be a symbol or a proc. Symbols refer to instance methods, and procs are evaluated in the controller at request time.
278
274
 
279
- Add conditional logic to authorization rules:
275
+ Dynamic rules can also be used without roles at all, allowing you to define custom logic or even delegate to custom policy objects:
280
276
 
281
277
  ```rb
282
- class OrdersController < ApplicationController
283
- # Method-based conditions
284
- grant_access roles: :manager, if: :company_manager?, unless: :suspended?
285
-
286
- # Proc-based conditions
287
- grant_access action: :show, roles: :client, if: -> { current_user.company == Order.find(params[:id]).company }
288
- def show
289
- # Accessible to company managers unless suspended, and to clients if the client's company matches the order's company
278
+ class InvoicesController < ApplicationController
279
+ grant_access action: :update, unless: -> { Date.current.on_weekend? }
280
+ def update
281
+ # ...
290
282
  end
291
283
 
292
- # Dynamic-only rules (no roles required, can be used with custom policies)
293
- grant_access action: :index, if: -> { OrdersPolicy.new(current_user).index? }
294
- def index
295
- # Accessible to company managers unless suspended, and to users based on custom policy logic
284
+ grant_access action: :destroy, if: :destroy_allowed?
285
+ def destroy
286
+ # ...
296
287
  end
297
288
 
298
289
  private
299
290
 
300
- def company_manager?
301
- current_user.manager_of?(Company.find(params[:company_id]))
291
+ def destroy_allowed?
292
+ InvoicePolicy.new(current_user).destroy?(Invoice.find(params[:id]))
302
293
  end
294
+ end
295
+ ```
296
+
297
+ ## When Unauthorized
303
298
 
304
- def suspended?
305
- current_user.suspended?
299
+ By default, when unauthorized, Rabarber will redirect back (HTML format) or return 403 (other formats). You can override `when_unauthorized` method to customize unauthorized access behavior:
300
+
301
+ ```rb
302
+ class ApplicationController < ActionController::Base
303
+ include Rabarber::Authorization
304
+
305
+ with_authorization
306
+
307
+ private
308
+
309
+ def when_unauthorized
310
+ head :not_found # Custom behavior to hide existence of protected resources
306
311
  end
307
312
  end
308
313
  ```
309
314
 
310
- ## Multi-tenancy / Context
315
+ The `when_unauthorized` method can be overridden in any controller to provide controller-specific unauthorized access handling.
316
+
317
+ ## Context / Multi-tenancy
311
318
 
312
- All Rabarber methods accept a `context` parameter, allowing you to work with roles within specific scopes. By default, context is `nil`, meaning roles are global.
319
+ Rabarber supports multi-tenancy through its context feature. All Rabarber methods accept a `context` parameter, allowing you to work with roles within specific scopes. By default, context is `nil`, meaning roles are global. Context can also be an instance of an `ActiveRecord` model or a class.
313
320
 
314
- ### Contextual Role Assignment
321
+ For example, in a project management app, you might want users to have different roles in different projects - someone could be an `owner` in one project but just a `member` in another.
322
+
323
+ ### Contextual Role Assignment and Queries
315
324
 
316
325
  ```rb
317
326
  # Assign roles within a specific model instance
@@ -329,7 +338,7 @@ user.has_role?(:admin, context: Project)
329
338
  user.revoke_roles(:owner, context: project)
330
339
 
331
340
  # Get user roles
332
- user.roles(context: Project)
341
+ user.roles(context: project)
333
342
 
334
343
  # Get users with a role
335
344
  User.with_role(:member, context: project)
@@ -353,6 +362,8 @@ Rabarber.roles(context: project)
353
362
 
354
363
  ### Contextual Authorization
355
364
 
365
+ In authorization rules, in addition to specifying context explicitly, you can also provide a proc or a symbol (similar to dynamic rules):
366
+
356
367
  ```rb
357
368
  class ProjectsController < ApplicationController
358
369
  grant_access roles: :admin, context: Project
@@ -377,11 +388,11 @@ class ProjectsController < ApplicationController
377
388
  end
378
389
  ```
379
390
 
380
- ### Orphaned Context
391
+ ### Orphaned Contextual Roles
381
392
 
382
393
  When a context object is deleted from your database, its associated roles become orphaned and ignored by Rabarber.
383
394
 
384
- To clean up orphaned context roles, use:
395
+ To clean up orphaned roles, use:
385
396
 
386
397
  ```rb
387
398
  Rabarber.prune
@@ -389,13 +400,13 @@ Rabarber.prune
389
400
 
390
401
  ### Context Migrations
391
402
 
392
- Handle context changes when models are renamed or removed. These are irreversible data migrations.
403
+ When you rename or remove models used as contexts, you need to update Rabarber's stored context data accordingly. Use these irreversible data migrations:
393
404
 
394
405
  ```rb
395
406
  # Rename a context class (e.g., when you rename your Ticket model to Task)
396
407
  migrate_authorization_context!("Ticket", "Task")
397
408
 
398
- # Remove orphaned context data (e.g., when you delete the Ticket model entirely)
409
+ # Remove context data (e.g., when you delete the Ticket model entirely)
399
410
  delete_authorization_context!("Ticket")
400
411
  ```
401
412
 
@@ -61,7 +61,7 @@ module Rabarber
61
61
  end
62
62
 
63
63
  def when_unauthorized
64
- request.format.html? ? redirect_back(fallback_location: root_path) : head(:forbidden)
64
+ request.format.html? ? redirect_back_or_to(root_path) : head(:forbidden)
65
65
  end
66
66
  end
67
67
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rabarber
4
- VERSION = "5.2.3"
4
+ VERSION = "5.2.5"
5
5
  end
data/rabarber.gemspec CHANGED
@@ -6,18 +6,20 @@ Gem::Specification.new do |spec|
6
6
  spec.name = "rabarber"
7
7
  spec.version = Rabarber::VERSION
8
8
  spec.authors = ["enjaku4", "trafium"]
9
- spec.email = ["enjaku4@icloud.com"]
9
+ spec.email = ["contact@brownbox.dev"]
10
10
  spec.homepage = "https://github.com/enjaku4/rabarber"
11
11
  spec.metadata["homepage_uri"] = spec.homepage
12
12
  spec.metadata["source_code_uri"] = spec.homepage
13
13
  spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
14
14
  spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
15
15
  spec.metadata["documentation_uri"] = "#{spec.homepage}/blob/main/README.md"
16
+ spec.metadata["mailing_list_uri"] = "#{spec.homepage}/discussions"
17
+ spec.metadata["funding_uri"] = "https://github.com/sponsors/enjaku4"
16
18
  spec.metadata["rubygems_mfa_required"] = "true"
17
19
  spec.summary = "Simple role-based authorization library for Ruby on Rails"
18
- spec.description = "Rabarber provides role-based authorization for Ruby on Rails applications with support for multi-tenancy, dynamic rules, and clean controller-level access control that separates authorization from business logic"
20
+ spec.description = "Simple role-based authorization for Rails applications with multi-tenancy support"
19
21
  spec.license = "MIT"
20
- spec.required_ruby_version = ">= 3.2", "< 3.5"
22
+ spec.required_ruby_version = ">= 3.2", "< 4.1"
21
23
 
22
24
  spec.files = [
23
25
  "rabarber.gemspec", "README.md", "CHANGELOG.md", "LICENSE.txt"
@@ -27,5 +29,5 @@ Gem::Specification.new do |spec|
27
29
 
28
30
  spec.add_dependency "dry-configurable", "~> 1.1"
29
31
  spec.add_dependency "dry-types", "~> 1.7"
30
- spec.add_dependency "rails", ">= 7.1", "< 8.1"
32
+ spec.add_dependency "rails", ">= 7.1", "< 8.2"
31
33
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rabarber
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.3
4
+ version: 5.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - enjaku4
@@ -47,7 +47,7 @@ dependencies:
47
47
  version: '7.1'
48
48
  - - "<"
49
49
  - !ruby/object:Gem::Version
50
- version: '8.1'
50
+ version: '8.2'
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
@@ -57,12 +57,11 @@ dependencies:
57
57
  version: '7.1'
58
58
  - - "<"
59
59
  - !ruby/object:Gem::Version
60
- version: '8.1'
61
- description: Rabarber provides role-based authorization for Ruby on Rails applications
62
- with support for multi-tenancy, dynamic rules, and clean controller-level access
63
- control that separates authorization from business logic
60
+ version: '8.2'
61
+ description: Simple role-based authorization for Rails applications with multi-tenancy
62
+ support
64
63
  email:
65
- - enjaku4@icloud.com
64
+ - contact@brownbox.dev
66
65
  executables: []
67
66
  extensions: []
68
67
  extra_rdoc_files: []
@@ -106,6 +105,8 @@ metadata:
106
105
  changelog_uri: https://github.com/enjaku4/rabarber/blob/main/CHANGELOG.md
107
106
  bug_tracker_uri: https://github.com/enjaku4/rabarber/issues
108
107
  documentation_uri: https://github.com/enjaku4/rabarber/blob/main/README.md
108
+ mailing_list_uri: https://github.com/enjaku4/rabarber/discussions
109
+ funding_uri: https://github.com/sponsors/enjaku4
109
110
  rubygems_mfa_required: 'true'
110
111
  rdoc_options: []
111
112
  require_paths:
@@ -117,7 +118,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
117
118
  version: '3.2'
118
119
  - - "<"
119
120
  - !ruby/object:Gem::Version
120
- version: '3.5'
121
+ version: '4.1'
121
122
  required_rubygems_version: !ruby/object:Gem::Requirement
122
123
  requirements:
123
124
  - - ">="