role_core 0.0.12 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +204 -10
- data/lib/generators/role_core/config/USAGE +2 -0
- data/lib/generators/role_core/config/config_generator.rb +14 -0
- data/lib/generators/role_core/config/templates/role_core.en.yml +20 -0
- data/lib/generators/role_core/config/templates/role_core.rb +70 -0
- data/lib/generators/role_core/model/USAGE +2 -0
- data/lib/generators/role_core/model/model_generator.rb +13 -0
- data/lib/generators/role_core/model/templates/role.rb +4 -0
- data/lib/role_core/version.rb +1 -1
- metadata +13 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c75876caf7676f2733564e2f0657b8625c798d29ee7de9e45a21bc66312e54d
|
4
|
+
data.tar.gz: 8bfb27b3b34481cb4cf566d3ff336e9450b45020a9109a201d7ac21e1e81194f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c4d3a8e2c38049412bc12f8e048093710ee3f929d9f6cac96525de98ecd6e1f8b4851792e905f8c0c2cc7a467a04cff9512c03d435d585b1c29c3e04b4fb437
|
7
|
+
data.tar.gz: fb14f0557dc1b7349b69e647297ebe3033b97138665b2c5314cccf5456933552aa6b0b6c906f258abf7a55be3f05e59e0e1a77ad26714151738e32e431da66bf
|
data/README.md
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
RoleCore
|
2
2
|
====
|
3
3
|
|
4
|
-
|
4
|
+
RoleCore is a Rails engine which could provide essential industry of Role-based access control.
|
5
5
|
|
6
6
|
<img width="550" alt="2018-03-12 10 12 21" src="https://user-images.githubusercontent.com/5518/37262401-e6c9d604-25dd-11e8-849d-7f7d923d5f18.png">
|
7
7
|
|
8
|
-
|
8
|
+
It's only provides the ability to define permissions and pre-made Role model.
|
9
9
|
|
10
|
-
|
10
|
+
In addition, it's not handle the authentication or authorization,
|
11
|
+
you should integrate with CanCanCan, Pundit or other solutions by yourself.
|
11
12
|
|
12
13
|
## Installation
|
13
14
|
|
@@ -17,13 +18,7 @@ Add this line to your Gemfile:
|
|
17
18
|
gem 'role_core'
|
18
19
|
```
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
```ruby
|
23
|
-
gem 'role_core', github: 'rails-engine/role_core'
|
24
|
-
```
|
25
|
-
|
26
|
-
And then execute:
|
21
|
+
Then execute:
|
27
22
|
|
28
23
|
```sh
|
29
24
|
$ bundle
|
@@ -41,8 +36,207 @@ Then do migrate
|
|
41
36
|
$ bin/rails db:migrate
|
42
37
|
```
|
43
38
|
|
39
|
+
Run config generator
|
40
|
+
|
41
|
+
```sh
|
42
|
+
$ bin/rails g role_core:config
|
43
|
+
```
|
44
|
+
|
45
|
+
Run model generator
|
46
|
+
|
47
|
+
```sh
|
48
|
+
$ bin/rails g role_core:model
|
49
|
+
```
|
50
|
+
|
51
|
+
## Getting Start
|
52
|
+
|
53
|
+
### Define permissions
|
54
|
+
|
55
|
+
Permissions are defined in `config/initializers/role_core.rb`,
|
56
|
+
checking it to know how to define permissions.
|
57
|
+
|
58
|
+
In addition, there also includes a directive about how to integrate with CanCanCan.
|
59
|
+
|
60
|
+
### Hook up to application
|
61
|
+
|
62
|
+
In order to obtain maximum customability, you need to hooking up role(s) to your user model by yourself.
|
63
|
+
|
64
|
+
#### For User who has single role
|
65
|
+
|
66
|
+
##### Create `one-to-many` relationship between Role and User
|
67
|
+
|
68
|
+
Generate `one-to-many` migration, adding `role_id` to `User` model
|
69
|
+
|
70
|
+
```sh
|
71
|
+
$ bin/rails g migration AddRoleToUsers role:references
|
72
|
+
```
|
73
|
+
|
74
|
+
Then do migrate
|
75
|
+
|
76
|
+
```sh
|
77
|
+
$ bin/rails db:migrate
|
78
|
+
```
|
79
|
+
|
80
|
+
Declare `a User belongs to a Role`
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
class User < ApplicationRecord
|
84
|
+
belongs_to :role
|
85
|
+
|
86
|
+
# ...
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
Declare `a Role has many Users`
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
class Role < RoleCore::Role
|
94
|
+
has_many :users
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
##### Check permission
|
99
|
+
|
100
|
+
Permssions you've defined will translate to a virtual model (a Class which implemented ActiveModel interface),
|
101
|
+
`permission` would be an attribute, `group` would be a nested virtual model (like ActiveRecord's `has_one` association).
|
102
|
+
|
103
|
+
So you can simply check permission like:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
user.role.permissions.read_public?
|
107
|
+
user.role.permissions.project.read? # `project` is a `group`
|
108
|
+
```
|
109
|
+
|
110
|
+
For better usage, you may delegate the `permissions` from `Role` model to `User`:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
class User < ApplicationRecord
|
114
|
+
belongs_to :role
|
115
|
+
|
116
|
+
delegate :permissions, to: :role
|
117
|
+
|
118
|
+
# ...
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
Then you can
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
user.permissions.read_public?
|
126
|
+
user.permissions.project.read?
|
127
|
+
```
|
128
|
+
|
129
|
+
_Keep in mind: fetching `role` will made a SQL query, you may need eager loading to avoid N+1 problem in some cases._
|
130
|
+
|
131
|
+
#### For User who has multiple roles
|
132
|
+
|
133
|
+
##### Create `many-to-many` relationship between Role and User
|
134
|
+
|
135
|
+
Generate a `many-to-many` intervening model
|
136
|
+
|
137
|
+
```sh
|
138
|
+
$ bin/rails g model RoleAssignment user:references role:references
|
139
|
+
```
|
140
|
+
|
141
|
+
Then do migrate
|
142
|
+
|
143
|
+
```sh
|
144
|
+
$ bin/rails db:migrate
|
145
|
+
```
|
146
|
+
|
147
|
+
Declare `a User has many Roles through RoleAssignments`
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
class User < ApplicationRecord
|
151
|
+
has_many :role_assignments, dependent: :destroy
|
152
|
+
has_many :roles, through: :role_assignments
|
153
|
+
|
154
|
+
# ...
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
Declare `a Role has many Users through RoleAssignments`
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
class Role < RoleCore::Role
|
162
|
+
has_many :role_assignments, dependent: :destroy
|
163
|
+
has_many :users, through: :role_assignments
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
##### Check permission
|
168
|
+
|
169
|
+
Permssions you've defined will translate to a virtual model (a Class which implemented ActiveModel interface),
|
170
|
+
`permission` would be an attribute, `group` would be a nested virtual model (like ActiveRecord's `has_one` association).
|
171
|
+
|
172
|
+
So you can simply check permission like:
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
user.roles.any? { |role| role.permissions.read_public? }
|
176
|
+
user.roles.any? { |role| role.permissions.project.read? } # `project` is a `group`
|
177
|
+
```
|
178
|
+
|
179
|
+
For better usage, you could declare a `can?` helper method:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
class User < ApplicationRecord
|
183
|
+
has_many :role_assignments, dependent: :destroy
|
184
|
+
has_many :roles, through: :role_assignments
|
185
|
+
|
186
|
+
def can?(&block)
|
187
|
+
roles.map(&:permissions).any?(&block)
|
188
|
+
end
|
189
|
+
|
190
|
+
# ...
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
Then you can
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
user.can? { |permissions| permissions.read_public? }
|
198
|
+
user.can? { |permissions| permissions.project.read? }
|
199
|
+
```
|
200
|
+
|
201
|
+
_Keep in mind: fetching `roles` will made a SQL query, you may need eager loading to avoid N+1 problem in some cases._
|
202
|
+
|
203
|
+
### Integrate with CanCanCan
|
204
|
+
|
205
|
+
Open `config/initializers/role_core.rb`, uncomment CanCanCan integration codes and follows samples to define permissions for CanCanCan
|
206
|
+
|
207
|
+
Open your User model:
|
208
|
+
|
209
|
+
- For a user who has single role:
|
210
|
+
|
211
|
+
Add a delegate to User model:
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
delegate :permitted_permissions, to: :role
|
215
|
+
```
|
216
|
+
|
217
|
+
- For a user who has multiple roles:
|
218
|
+
|
219
|
+
Add a `permitted_permissions` public method to User model:
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
def permitted_permissions
|
223
|
+
roles.map(&:permitted_permissions).reduce(RoleCore::ComputedPermissions.new, &:concat)
|
224
|
+
end
|
225
|
+
```
|
226
|
+
|
227
|
+
Open `app/models/ability.rb`, add `user.permitted_permissions.call(self, user)` to `initialize` method.
|
228
|
+
|
229
|
+
You can check RoleCore's Demo (see below) for better understanding.
|
230
|
+
|
231
|
+
### Management UI
|
232
|
+
|
233
|
+
See [RolesController in dummy app](https://github.com/rails-engine/role_core/blob/master/test/dummy/app/controllers/roles_controller.rb)
|
234
|
+
and relates [view](https://github.com/rails-engine/role_core/blob/master/test/dummy/app/views/roles/_form.html.erb).
|
235
|
+
|
44
236
|
## Demo
|
45
237
|
|
238
|
+
The dummy app shows a simple multiple roles with CanCanCan integration includes management UI.
|
239
|
+
|
46
240
|
Clone the repository.
|
47
241
|
|
48
242
|
```sh
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RoleCore
|
4
|
+
module Generators
|
5
|
+
class ConfigGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path("../templates", __FILE__)
|
7
|
+
|
8
|
+
def generate_config
|
9
|
+
copy_file "role_core.rb", "config/initializers/role_core.rb"
|
10
|
+
copy_file "role_core.en.yml", "config/locales/role_core.en.yml"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
en:
|
2
|
+
role_core:
|
3
|
+
models: # Defined by `group` place here
|
4
|
+
# project: Project
|
5
|
+
# task: Task
|
6
|
+
attributes:
|
7
|
+
# global: # Top-level permissions
|
8
|
+
# foo: Foo
|
9
|
+
# bar: Bar
|
10
|
+
# project:
|
11
|
+
# create: New project
|
12
|
+
# destroy: Destroy project
|
13
|
+
# update: Edit project
|
14
|
+
# read: Read project
|
15
|
+
# read_public: Read public project
|
16
|
+
# task:
|
17
|
+
# create: New task
|
18
|
+
# destroy: Destroy task
|
19
|
+
# update: Edit task
|
20
|
+
# update_my_own: Edit my own task
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Uncomment below if you want to integrate with CanCanCan
|
4
|
+
#
|
5
|
+
# require "role_core/contrib/can_can_can_permission"
|
6
|
+
# RoleCore.permission_class = RoleCore::CanCanCanPermission
|
7
|
+
|
8
|
+
RoleCore.permission_set_class.draw do
|
9
|
+
# Define permissions for the application. For example:
|
10
|
+
#
|
11
|
+
# permission :foo, default: true # `default: true` means grant to user by default
|
12
|
+
# permission :bar
|
13
|
+
#
|
14
|
+
# You can also group permissions by using `group`:
|
15
|
+
#
|
16
|
+
# group :project do
|
17
|
+
# permission :create
|
18
|
+
# permission :destroy
|
19
|
+
# permission :update
|
20
|
+
# permission :read
|
21
|
+
# permission :read_public
|
22
|
+
#
|
23
|
+
# # `group` supports nesting
|
24
|
+
# group :task do
|
25
|
+
# permission :create
|
26
|
+
# permission :destroy
|
27
|
+
# permission :update
|
28
|
+
# permission :read
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# For CanCanCan integration, you can pass `model_name` for `group` or `permission`. For example:
|
33
|
+
#
|
34
|
+
# group :project, model_name: "Project" do
|
35
|
+
# permission :create
|
36
|
+
# permission :destroy, model_name: 'Plan'
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# That will translate to CanCanCan's abilities (if user has these permissions),
|
40
|
+
# the permission's name will be the action:
|
41
|
+
#
|
42
|
+
# can :create, Project
|
43
|
+
# can :destroy, Plan
|
44
|
+
#
|
45
|
+
# You can pass `priority` argument to `permission`
|
46
|
+
#
|
47
|
+
# group :project, model_name: "Project" do
|
48
|
+
# permission :read_public,
|
49
|
+
# permission :read, priority: 1
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# That will made 'read' prior than `read_public`.
|
53
|
+
#
|
54
|
+
# For CanCanCan's hash of conditions
|
55
|
+
# (see https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities#hash-of-conditions)
|
56
|
+
# you can simply pass them as arguments for `permission` even with a block
|
57
|
+
#
|
58
|
+
# group :task, model_name: "Task" do
|
59
|
+
# permission :read_public, is_public: true
|
60
|
+
# permission :update_my_own, action: :update, default: true do |user, task|
|
61
|
+
# task.user_id == user.id
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# Although permission's name will be CanCanCan's action by default,
|
66
|
+
# you can pass `action` argument to override it.
|
67
|
+
#
|
68
|
+
# permission :read_public, action: :read, is_public: true
|
69
|
+
#
|
70
|
+
end.finalize! # Call `finalize!` to freezing the definition, that's optional.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RoleCore
|
4
|
+
module Generators
|
5
|
+
class ModelGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path("../templates", __FILE__)
|
7
|
+
|
8
|
+
def generate_model
|
9
|
+
copy_file "role.rb", "app/models/role.rb"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/role_core/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: role_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jasl
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -44,7 +44,8 @@ dependencies:
|
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '0'
|
47
|
-
description:
|
47
|
+
description: RoleCore is a Rails engine which could provide essential industry of
|
48
|
+
Role-based access control.
|
48
49
|
email:
|
49
50
|
- jasl9187@hotmail.com
|
50
51
|
executables: []
|
@@ -57,6 +58,13 @@ files:
|
|
57
58
|
- app/models/role_core/application_record.rb
|
58
59
|
- app/models/role_core/role.rb
|
59
60
|
- db/migrate/20170705174003_create_roles.rb
|
61
|
+
- lib/generators/role_core/config/USAGE
|
62
|
+
- lib/generators/role_core/config/config_generator.rb
|
63
|
+
- lib/generators/role_core/config/templates/role_core.en.yml
|
64
|
+
- lib/generators/role_core/config/templates/role_core.rb
|
65
|
+
- lib/generators/role_core/model/USAGE
|
66
|
+
- lib/generators/role_core/model/model_generator.rb
|
67
|
+
- lib/generators/role_core/model/templates/role.rb
|
60
68
|
- lib/role_core.rb
|
61
69
|
- lib/role_core/computed_permissions.rb
|
62
70
|
- lib/role_core/concerns/models/role.rb
|
@@ -90,5 +98,6 @@ rubyforge_project:
|
|
90
98
|
rubygems_version: 2.7.6
|
91
99
|
signing_key:
|
92
100
|
specification_version: 4
|
93
|
-
summary:
|
101
|
+
summary: RoleCore is a Rails engine which could provide essential industry of Role-based
|
102
|
+
access control.
|
94
103
|
test_files: []
|