bullet_train-roles 0.1.0 → 0.1.4
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 +4 -4
- data/Gemfile.lock +3 -2
- data/README.md +17 -11
- data/bin/setup +6 -0
- data/lib/bullet_train/roles/version.rb +1 -1
- data/lib/bullet_train/roles.rb +1 -0
- data/lib/generators/bullet_train/roles/install/install_generator.rb +33 -20
- data/lib/generators/bullet_train/roles/install/templates/roles.yml +0 -2
- data/lib/models/role.rb +5 -9
- data/lib/roles/support.rb +2 -2
- data/lib/roles/user.rb +26 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f03a796a2c17954ad4c25e313caea68ba0b60b7e8901e7c1acf83d869e100592
|
4
|
+
data.tar.gz: 131e6518cefb00c6ea280d4ac4bf492961cb6f45b6d0ef3d695b66de9366d906
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7df53d71fb2d393e84a30a5efb1fa9f351781653b40e1cc31e5cf565d4432228b3a78b6924d021908c5d463695dfdeb0dff834a0f1c63a26438774e8159f4438
|
7
|
+
data.tar.gz: 56a0c8b76f5105959d828db3f619c863cc917fd3caf1e8dc838151268da68da1bce455ebd3378f68dfa7bf78d804d673df311f6351cfd0a47a2b4f43a6c68c07
|
data/Gemfile.lock
CHANGED
@@ -9,7 +9,7 @@ GIT
|
|
9
9
|
PATH
|
10
10
|
remote: .
|
11
11
|
specs:
|
12
|
-
bullet_train-roles (0.1.
|
12
|
+
bullet_train-roles (0.1.4)
|
13
13
|
active_hash
|
14
14
|
activesupport
|
15
15
|
cancancan
|
@@ -173,6 +173,7 @@ GEM
|
|
173
173
|
|
174
174
|
PLATFORMS
|
175
175
|
arm64-darwin-20
|
176
|
+
arm64-darwin-21
|
176
177
|
|
177
178
|
DEPENDENCIES
|
178
179
|
active_hash!
|
@@ -187,4 +188,4 @@ DEPENDENCIES
|
|
187
188
|
standard (~> 1.5.0)
|
188
189
|
|
189
190
|
BUNDLED WITH
|
190
|
-
2.
|
191
|
+
2.3.4
|
data/README.md
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
# Bullet Train Roles
|
2
2
|
|
3
|
-
|
3
|
+
Bullet Train Roles provides a Yaml-based configuration layer on top of [CanCanCan](https://github.com/CanCanCommunity/cancancan). You can use this configuration file to simplify the definition of many common permissions, while still implementing more complicated permissions in CanCanCan's traditional `app/model/ability.rb`.
|
4
4
|
|
5
|
-
|
5
|
+
Additionally, Bullet Train Roles makes it trivial to assign the same roles and associated permissions at different levels in your application. For example, you can assign someone administrative privileges at a team level, or only at a project level.
|
6
|
+
|
7
|
+
Bullet Train Roles was created by [Andrew Culver](http://twitter.com/andrewculver) and [Adam Pallozzi](https://twitter.com/adampallozzi).
|
8
|
+
|
9
|
+
## Example Domain Model
|
6
10
|
|
7
11
|
For the sake of this document, we're going to assume the following example modeling around users and teams:
|
8
12
|
|
@@ -11,18 +15,21 @@ For the sake of this document, we're going to assume the following example model
|
|
11
15
|
- A `Membership` can have zero, one, or many `Role`s assigned.
|
12
16
|
- A `Membership` without a `Role` is just a default team member.
|
13
17
|
|
14
|
-
You don't have to name your models the same thing in order to use this Ruby Gem, but it does depend on having a similar structure.
|
18
|
+
You don't have to name your models the same thing in order to use this Ruby Gem, but it does depend on having a similar structure.
|
15
19
|
|
16
20
|
> If you're interested in reading more about how and why Bullet Train implements this structure, you can [read about it on our blog](https://blog.bullettrain.co/teams-should-be-an-mvp-feature/).
|
17
21
|
|
18
22
|
## Installation
|
19
23
|
|
20
|
-
Add
|
24
|
+
Add these lines to your application's Gemfile:
|
21
25
|
|
22
26
|
```ruby
|
27
|
+
gem "active_hash", github: "bullet-train-co/active_hash"
|
23
28
|
gem "bullet_train-roles"
|
24
29
|
```
|
25
30
|
|
31
|
+
> We have to link to a specific downstream version of ActiveHash temporarily while working to merge certain fixes and updates upstream.
|
32
|
+
|
26
33
|
And then execute the following in your shell:
|
27
34
|
|
28
35
|
```
|
@@ -32,25 +39,24 @@ bundle install
|
|
32
39
|
Finally, run the installation generator:
|
33
40
|
|
34
41
|
```
|
35
|
-
rails generate bullet_train:roles:install
|
42
|
+
rails generate bullet_train:roles:install
|
36
43
|
```
|
37
44
|
|
38
|
-
|
45
|
+
The installer defaults to installing a configuration for `Membership` and `Team`, but it will prompt you so you can specify different models if they differ in your application.
|
46
|
+
|
47
|
+
The installer will:
|
39
48
|
|
40
49
|
- stub out a configuration file in `config/models/roles.yml`.
|
41
50
|
- create a database migration to add `role_ids:jsonb` to `Membership`.
|
42
51
|
- add `include Role::Support` to `app/models/membership.rb`.
|
43
52
|
- add a basic `permit` call in `app/models/ability.rb`.
|
44
53
|
|
45
|
-
### Limitations
|
46
|
-
|
47
|
-
The generators currently assume you're using PostgreSQL and `jsonb` will be available when generating a `role_ids` column. If you're using MySQL, you can edit these migrations and use `json` instead, although you won't be able to set a default value and you'll need to take care of this in the model.
|
48
54
|
|
49
55
|
## Usage
|
50
56
|
|
51
|
-
The provided `Role` model is backed
|
57
|
+
The provided `Role` model is backed by a Yaml configuration in `config/models/roles.yml`.
|
52
58
|
|
53
|
-
To help explain this configuration and
|
59
|
+
To help explain this configuration and its options, we'll provide the following hypothetical example:
|
54
60
|
|
55
61
|
```
|
56
62
|
default:
|
data/bin/setup
CHANGED
data/lib/bullet_train/roles.rb
CHANGED
@@ -31,6 +31,7 @@ module BulletTrain
|
|
31
31
|
# TODO: follow back Andrew on question about this in Slack
|
32
32
|
|
33
33
|
add_permit_to_ability_model(top_level_model, associated_model)
|
34
|
+
add_concern_to_user
|
34
35
|
end
|
35
36
|
|
36
37
|
private
|
@@ -46,7 +47,7 @@ module BulletTrain
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def db_adapter
|
49
|
-
allowed_adapter_types = %w[mysql sqlite postgresql]
|
50
|
+
allowed_adapter_types = %w[mysql mysql2 sqlite postgresql]
|
50
51
|
|
51
52
|
adapter_name = ActiveRecord::Base.connection.adapter_name.downcase
|
52
53
|
|
@@ -89,14 +90,6 @@ module BulletTrain
|
|
89
90
|
File.write(file_location, update_file_content.join)
|
90
91
|
end
|
91
92
|
|
92
|
-
def add_default_value_to_migration(file_name, table_name)
|
93
|
-
file_location = Dir["db/migrate/*_#{file_name}.rb"].last
|
94
|
-
line_to_match = "add_column :#{table_name.downcase}, :role_ids"
|
95
|
-
content_to_add = ", default: []\n"
|
96
|
-
|
97
|
-
add_in_file(file_location, line_to_match, content_to_add)
|
98
|
-
end
|
99
|
-
|
100
93
|
def migration_file_exists?(file_name)
|
101
94
|
file_location = Dir["db/migrate/*_#{file_name}.rb"].last
|
102
95
|
|
@@ -118,8 +111,6 @@ module BulletTrain
|
|
118
111
|
|
119
112
|
generate "migration", "#{migration_file_name} role_ids:#{json_data_type_identifier}"
|
120
113
|
|
121
|
-
add_default_value_to_migration(migration_file_name, top_level_model_table_name)
|
122
|
-
|
123
114
|
puts("Success 🎉🎉\n\n")
|
124
115
|
end
|
125
116
|
|
@@ -160,22 +151,44 @@ module BulletTrain
|
|
160
151
|
end
|
161
152
|
|
162
153
|
def add_permit_to_ability_model(top_level_model, associated_model)
|
163
|
-
# TODO: need to make this more smart e.g.
|
164
|
-
# 1. should know what parameter is used for user e.g. def initialize(user)
|
165
|
-
# 2. what if code doesn't include "if user.present?", maybe we need to handle that, consult with Andrew
|
166
154
|
file_location = "app/models/ability.rb"
|
167
|
-
line_to_match = "
|
168
|
-
content_to_add = "\n
|
169
|
-
|
170
|
-
puts("Adding 'permit user, through: :#{top_level_model.downcase}, parent: :#{associated_model.downcase}' to #{associated_model}\n\n")
|
155
|
+
line_to_match = "include CanCan::Ability"
|
156
|
+
content_to_add = "\n include Roles::Permit\n"
|
157
|
+
puts("Adding 'include Roles::Permit' to #{associated_model}\n\n")
|
171
158
|
|
172
159
|
if line_exists_in_file?(file_location, content_to_add)
|
173
160
|
message = "#{remove_new_lines_and_spaces(content_to_add)} already exists in #{associated_model}!!\n\n"
|
161
|
+
line_already_exists(message)
|
162
|
+
else
|
163
|
+
add_in_file(file_location, line_to_match, content_to_add)
|
164
|
+
end
|
174
165
|
|
175
|
-
|
166
|
+
line_to_match = "def initialize(user)"
|
167
|
+
content_to_add = "\n permit user, through: :#{top_level_model.downcase.pluralize}, parent: :#{associated_model.downcase} if user.present?\n"
|
168
|
+
puts("Adding 'permit' to #{associated_model}\n\n")
|
169
|
+
|
170
|
+
if line_exists_in_file?(file_location, content_to_add)
|
171
|
+
message = "#{remove_new_lines_and_spaces(content_to_add)} already exists in #{associated_model}!!\n\n"
|
172
|
+
line_already_exists(message)
|
173
|
+
else
|
174
|
+
add_in_file(file_location, line_to_match, content_to_add)
|
176
175
|
end
|
177
176
|
|
178
|
-
|
177
|
+
puts("Success 🎉🎉\n\n")
|
178
|
+
end
|
179
|
+
|
180
|
+
def add_concern_to_user
|
181
|
+
file_location = "app/models/user.rb"
|
182
|
+
line_to_match = "class User < ApplicationRecord"
|
183
|
+
content_to_add = "\n include Roles::User\n"
|
184
|
+
puts("Adding 'include Roles::User' to User\n\n")
|
185
|
+
|
186
|
+
if line_exists_in_file?(file_location, content_to_add)
|
187
|
+
message = "#{remove_new_lines_and_spaces(content_to_add)} already exists in User!!\n\n"
|
188
|
+
line_already_exists(message)
|
189
|
+
else
|
190
|
+
add_in_file(file_location, line_to_match, content_to_add)
|
191
|
+
end
|
179
192
|
|
180
193
|
puts("Success 🎉🎉\n\n")
|
181
194
|
end
|
data/lib/models/role.rb
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
require "active_hash"
|
4
4
|
|
5
|
-
class RemovingLastTeamAdminException < RuntimeError; end
|
6
|
-
|
7
5
|
class Role < ActiveYaml::Base
|
8
6
|
include ActiveYaml::Aliases
|
9
7
|
set_root_path "config/models"
|
@@ -111,23 +109,21 @@ class Role < ActiveYaml::Base
|
|
111
109
|
class Collection < Array
|
112
110
|
def initialize(model, ary)
|
113
111
|
@model = model
|
114
|
-
|
115
112
|
super(ary)
|
116
113
|
end
|
117
114
|
|
118
115
|
def <<(role)
|
119
116
|
return true if include?(role)
|
120
|
-
|
121
|
-
role_ids = @model.role_ids
|
122
|
-
|
117
|
+
role_ids = @model.role_ids || []
|
123
118
|
role_ids << role.id
|
124
|
-
|
125
119
|
@model.update(role_ids: role_ids)
|
126
120
|
end
|
127
121
|
|
128
122
|
def delete(role)
|
129
|
-
@model.
|
130
|
-
|
123
|
+
return @model.save unless include?(role)
|
124
|
+
current_role_ids = @model.role_ids || []
|
125
|
+
new_role_ids = current_role_ids - [role.key]
|
126
|
+
@model.role_ids = new_role_ids
|
131
127
|
@model.save
|
132
128
|
end
|
133
129
|
end
|
data/lib/roles/support.rb
CHANGED
@@ -44,7 +44,7 @@ module Roles
|
|
44
44
|
after_destroy :invalidate_cache
|
45
45
|
|
46
46
|
def validate_roles
|
47
|
-
self.role_ids = role_ids
|
47
|
+
self.role_ids = role_ids&.select(&:present?) || []
|
48
48
|
|
49
49
|
return if @allowed_roles.nil?
|
50
50
|
|
@@ -66,7 +66,7 @@ module Roles
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def roles_without_defaults
|
69
|
-
role_ids
|
69
|
+
role_ids&.map { |role_id| Role.find(role_id) } || []
|
70
70
|
end
|
71
71
|
|
72
72
|
def manageable_roles
|
data/lib/roles/user.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support"
|
4
|
+
|
5
|
+
module Roles
|
6
|
+
module User
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
def parent_ids_for(role, through, parent)
|
11
|
+
parent_id_column = "#{parent}_id"
|
12
|
+
key = "#{role.key}_#{through}_#{parent_id_column}s"
|
13
|
+
# TODO Maybe we should make ability caching a default feature of the gem?
|
14
|
+
# If we do that, we would just make it check whether `ability_cache` exists.
|
15
|
+
# return ability_cache[key] if ability_cache && ability_cache[key]
|
16
|
+
role = nil if role.default?
|
17
|
+
value = send(through).with_role(role).distinct.pluck(parent_id_column)
|
18
|
+
# TODO Maybe we should make ability caching a default feature of the gem?
|
19
|
+
# current_cache = ability_cache || {}
|
20
|
+
# current_cache[key] = value
|
21
|
+
# update_column :ability_cache, current_cache
|
22
|
+
value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet_train-roles
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Prabin Poudel
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-
|
12
|
+
date: 2022-02-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: byebug
|
@@ -192,6 +192,7 @@ files:
|
|
192
192
|
- lib/models/role.rb
|
193
193
|
- lib/roles/permit.rb
|
194
194
|
- lib/roles/support.rb
|
195
|
+
- lib/roles/user.rb
|
195
196
|
homepage: https://github.com/bullet-train-co/bullet_train-roles
|
196
197
|
licenses:
|
197
198
|
- MIT
|