rabarber 1.2.2 → 1.3.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: '084b409c4886e7622ee37f20b8f00c0d6e083546394bf3617bdd5277548a2764'
4
- data.tar.gz: 62c3f5fb0496fc5a0cf95f04f0f04d26ba4f847bdf1e838c248361dca72744ee
3
+ metadata.gz: 77a15b7eb4164c74d70e81d34630d6051915acc2abe35896df8938d9cc53e473
4
+ data.tar.gz: 847f675e00e9a85a158032af7ddc158f3189df78d4e6dae4ce15e2fe5024515e
5
5
  SHA512:
6
- metadata.gz: 0a1b141efb53f2b863f0dbbd1fe4c03ce199b7278bc0c51f8868866b918ea3161b8aebd9920872b43d9aea8cf24c5161b0f87d6d535a7c76295aa7890ee4b337
7
- data.tar.gz: b740291aba6e4d1c529453e990c30e009b5215ccbdc99a5eac6c1b8c21d354c813e5bdd3f700c37e9aa22d528b025814ce69629aedb95449108a704e233c53d2
6
+ metadata.gz: 7d16835ed84fd9ee2c2e7871080c5256bad34944ee0c1a3448c609f14732f1c7901539c0287bc5206feddb79ef77ee4aa001dd26a642d7c23b05498f5a668659
7
+ data.tar.gz: 0bd35329a6608d4f6680b4aba7882d015df36f38e0b0d963c9df988edd40e490e67180e504b1901f05c957e27f8bffe585372f6494ccad2989310daaa7feec68
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 1.3.0
2
+
3
+ - Add methods to directly add, rename, and remove roles
4
+ - `HasRoles#assign_roles` and `HasRoles#revoke_roles` methods now return the list of roles assigned to the user
5
+ - Minor performance improvements
6
+
1
7
  ## 1.2.2
2
8
 
3
9
  - Refactor to improve readability and maintainability
data/README.md CHANGED
@@ -67,16 +67,16 @@ Rabarber can be configured by using `.configure` method in an initializer:
67
67
 
68
68
  ```rb
69
69
  Rabarber.configure do |config|
70
- config.cache_enabled = false
71
- config.current_user_method = :authenticated_user
72
- config.must_have_roles = true
70
+ config.cache_enabled = true
71
+ config.current_user_method = :current_user
72
+ config.must_have_roles = false
73
73
  config.when_actions_missing = -> (missing_actions, context) { ... }
74
74
  config.when_roles_missing = -> (missing_roles, context) { ... }
75
75
  config.when_unauthorized = -> (controller) { ... }
76
76
  end
77
77
  ```
78
78
 
79
- - `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 the `Rabarber::Cache.clear` method.
79
+ - `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.
80
80
 
81
81
  - `current_user_method` must be a symbol representing the method that returns the currently authenticated user. The default value is `:current_user`.
82
82
 
@@ -112,6 +112,7 @@ By default, `#assign_roles` method will automatically create any roles that don'
112
112
  ```rb
113
113
  user.assign_roles(:accountant, :marketer, create_new: false)
114
114
  ```
115
+ The method returns an array of roles assigned to the user.
115
116
 
116
117
  **`#revoke_roles`**
117
118
 
@@ -122,6 +123,8 @@ user.revoke_roles(:accountant, :marketer)
122
123
  ```
123
124
  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.
124
125
 
126
+ The method returns an array of roles assigned to the user.
127
+
125
128
  **`#has_role?`**
126
129
 
127
130
  To check whether the user has a role, use:
@@ -140,6 +143,51 @@ To view all the roles assigned to the user, use:
140
143
  user.roles
141
144
  ```
142
145
 
146
+ ---
147
+
148
+ To manipulate roles directly, you can use `Rabarber::Role` methods:
149
+
150
+ **`.add`**
151
+
152
+ To add a new role, use:
153
+
154
+ ```rb
155
+ Rabarber::Role.add(:admin)
156
+ ```
157
+
158
+ This will create a new role with the specified name and return `true`. If the role already exists, it will return `false`.
159
+
160
+ **`.rename`**
161
+
162
+ To rename a role, use:
163
+
164
+ ```rb
165
+ Rabarber::Role.rename(:admin, :administrator)
166
+ ```
167
+ 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`.
168
+
169
+ The method won't rename the role if it is assigned to any user. To force the rename, use the method with `force: true` argument:
170
+ ```rb
171
+ Rabarber::Role.rename(:admin, :administrator, force: true)
172
+ ```
173
+
174
+ **`.remove`**
175
+
176
+ To remove a role, use:
177
+
178
+ ```rb
179
+ Rabarber::Role.remove(:admin)
180
+ ```
181
+
182
+ This will remove the role and return `true`. If the role doesn't exist, it will return `false`.
183
+
184
+ The method won't remove the role if it is assigned to any user. To force the removal, use the method with `force: true` argument:
185
+ ```rb
186
+ Rabarber::Role.remove(:admin, force: true)
187
+ ```
188
+
189
+ **`.names`**
190
+
143
191
  If you need to list all the role names available in your application, use:
144
192
 
145
193
  ```rb
@@ -10,16 +10,16 @@ module Rabarber
10
10
  enabled? ? Rails.cache.fetch(key, options, &block) : yield
11
11
  end
12
12
 
13
- def delete(key)
14
- Rails.cache.delete(key) if enabled?
13
+ def delete(*keys)
14
+ Rails.cache.delete_multi(keys) if enabled?
15
15
  end
16
16
 
17
17
  def enabled?
18
18
  Rabarber::Configuration.instance.cache_enabled
19
19
  end
20
20
 
21
- def key_for(record)
22
- "rabarber:roles_#{record.public_send(record.class.primary_key)}"
21
+ def key_for(id)
22
+ "rabarber:roles_#{id}"
23
23
  end
24
24
 
25
25
  def clear
@@ -17,7 +17,7 @@ module Rabarber
17
17
  end
18
18
 
19
19
  def roles
20
- Rabarber::Cache.fetch(Rabarber::Cache.key_for(self), expires_in: 1.hour, race_condition_ttl: 5.seconds) do
20
+ Rabarber::Cache.fetch(Rabarber::Cache.key_for(roleable_id), expires_in: 1.hour, race_condition_ttl: 5.seconds) do
21
21
  rabarber_roles.names
22
22
  end
23
23
  end
@@ -31,15 +31,25 @@ module Rabarber
31
31
 
32
32
  create_new_roles(roles_to_assign) if create_new
33
33
 
34
- rabarber_roles << Rabarber::Role.where(name: roles_to_assign) - rabarber_roles
34
+ new_roles = Rabarber::Role.where(name: roles_to_assign) - rabarber_roles
35
35
 
36
- delete_cache
36
+ if new_roles.any?
37
+ delete_roleable_cache
38
+ rabarber_roles << new_roles
39
+ end
40
+
41
+ roles
37
42
  end
38
43
 
39
44
  def revoke_roles(*role_names)
40
- self.rabarber_roles = rabarber_roles - Rabarber::Role.where(name: process_role_names(role_names))
45
+ new_roles = rabarber_roles - Rabarber::Role.where(name: process_role_names(role_names))
46
+
47
+ if rabarber_roles != new_roles
48
+ delete_roleable_cache
49
+ self.rabarber_roles = new_roles
50
+ end
41
51
 
42
- delete_cache
52
+ roles
43
53
  end
44
54
 
45
55
  private
@@ -53,8 +63,12 @@ module Rabarber
53
63
  Rabarber::Input::Roles.new(role_names).process
54
64
  end
55
65
 
56
- def delete_cache
57
- Rabarber::Cache.delete(Rabarber::Cache.key_for(self))
66
+ def delete_roleable_cache
67
+ Rabarber::Cache.delete(Rabarber::Cache.key_for(roleable_id))
68
+ end
69
+
70
+ def roleable_id
71
+ public_send(self.class.primary_key)
58
72
  end
59
73
  end
60
74
  end
@@ -6,16 +6,66 @@ module Rabarber
6
6
 
7
7
  validates :name, presence: true, uniqueness: true, format: { with: Rabarber::Input::Roles::REGEX }
8
8
 
9
- after_commit :delete_cache
9
+ has_and_belongs_to_many :roleables, join_table: "rabarber_roles_roleables"
10
10
 
11
- def self.names
12
- pluck(:name).map(&:to_sym)
13
- end
11
+ class << self
12
+ def names
13
+ pluck(:name).map(&:to_sym)
14
+ end
15
+
16
+ def add(name)
17
+ name = process_role_name(name)
18
+
19
+ return false if exists?(name: name)
20
+
21
+ delete_roles_cache
22
+
23
+ !!create!(name: name)
24
+ end
25
+
26
+ def rename(old_name, new_name, force: false)
27
+ role = find_by(name: process_role_name(old_name))
28
+ name = process_role_name(new_name)
29
+
30
+ return false if !role || exists?(name: name) || assigned_to_roleables(role).any? && !force
31
+
32
+ delete_roles_cache
33
+ delete_roleables_cache(role)
34
+
35
+ role.update!(name: name)
36
+ end
37
+
38
+ def remove(name, force: false)
39
+ role = find_by(name: process_role_name(name))
40
+
41
+ return false if !role || assigned_to_roleables(role).any? && !force
42
+
43
+ delete_roles_cache
44
+ delete_roleables_cache(role)
45
+
46
+ !!role.destroy!
47
+ end
48
+
49
+ private
50
+
51
+ def delete_roles_cache
52
+ Rabarber::Cache.delete(Rabarber::Cache::ALL_ROLES_KEY)
53
+ end
54
+
55
+ def delete_roleables_cache(role)
56
+ keys = assigned_to_roleables(role).map { |roleable_id| Rabarber::Cache.key_for(roleable_id) }
57
+ Rabarber::Cache.delete(*keys) if keys.any?
58
+ end
14
59
 
15
- private
60
+ def assigned_to_roleables(role)
61
+ ActiveRecord::Base.connection.select_values(
62
+ "SELECT roleable_id FROM rabarber_roles_roleables WHERE role_id = #{role.id}"
63
+ )
64
+ end
16
65
 
17
- def delete_cache
18
- Rabarber::Cache.delete(Rabarber::Cache::ALL_ROLES_KEY)
66
+ def process_role_name(name)
67
+ Rabarber::Input::Roles.new(name).process[0]
68
+ end
19
69
  end
20
70
  end
21
71
  end
@@ -15,22 +15,24 @@ module Rabarber
15
15
  @storage = { controller_rules: Hash.new({}), action_rules: Hash.new([]) }
16
16
  end
17
17
 
18
- def self.add(controller, action, roles, dynamic_rule, negated_dynamic_rule)
19
- rule = Rabarber::Rule.new(action, roles, dynamic_rule, negated_dynamic_rule)
20
-
21
- if action
22
- instance.storage[:action_rules][controller] += [rule]
23
- else
24
- instance.storage[:controller_rules][controller] = rule
18
+ class << self
19
+ def add(controller, action, roles, dynamic_rule, negated_dynamic_rule)
20
+ rule = Rabarber::Rule.new(action, roles, dynamic_rule, negated_dynamic_rule)
21
+
22
+ if action
23
+ instance.storage[:action_rules][controller] += [rule]
24
+ else
25
+ instance.storage[:controller_rules][controller] = rule
26
+ end
25
27
  end
26
- end
27
28
 
28
- def self.controller_rules
29
- instance.storage[:controller_rules]
30
- end
29
+ def controller_rules
30
+ instance.storage[:controller_rules]
31
+ end
31
32
 
32
- def self.action_rules
33
- instance.storage[:action_rules]
33
+ def action_rules
34
+ instance.storage[:action_rules]
35
+ end
34
36
  end
35
37
  end
36
38
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rabarber
4
- VERSION = "1.2.2"
4
+ VERSION = "1.3.0"
5
5
  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: 1.2.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - enjaku4
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-02-10 00:00:00.000000000 Z
12
+ date: 2024-02-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -80,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
82
  requirements: []
83
- rubygems_version: 3.2.33
83
+ rubygems_version: 3.3.26
84
84
  signing_key:
85
85
  specification_version: 4
86
86
  summary: Simple authorization library for Ruby on Rails.